2013-05-09 18 views
7

Mam trudności z wiązaniem danych na moich niestandardowych kontrolkach użytkownika. Stworzyłem przykładowy projekt, aby podkreślić mój problem. Jestem całkowicie nowy w WPF i zasadniczo również w MVVM, więc proszę o mnie ...Powiązanie w zależności od właściwości niestandardowej Kontrola użytkownika nie jest aktualizowana po zmianie

Stworzyłem prosty widok, który wykorzystuje wiązanie danych na dwa sposoby. Databinding na wbudowanym sterowaniu działa dobrze. Moja kontrola niestandardowa nie ... Postawiłem punkt kontrolny w mojej kontroli. Zostaje trafiony raz podczas uruchamiania, ale nigdy więcej. Tymczasem etykieta, którą związałem z tą samą wartością, radośnie się odlicza.

Czego mi brakuje? Mój przykład projekt następująco:

Okno główne:

<Window x:Class="WpfMVVMApp.MainWindow" 
     xmlns:local="clr-namespace:WpfMVVMApp" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
     <Grid.DataContext> 
      <local:CountdownViewModel /> 
     </Grid.DataContext> 
     <Label Name="custName" Content="{Binding Path=Countdown.ChargeTimeRemaining_Mins}" Height="45" VerticalAlignment="Top"></Label> 
     <local:UserControl1 MinutesRemaining="{Binding Path=Countdown.ChargeTimeRemaining_Mins}" Height="45"></local:UserControl1> 
    </Grid> 
</Window> 

Oto mój model:

namespace WpfMVVMApp 
{ 

    public class CountdownModel : INotifyPropertyChanged 
    { 
     private int chargeTimeRemaining_Mins; 
     public int ChargeTimeRemaining_Mins 
     { 
      get 
      { 
       return chargeTimeRemaining_Mins; 
      } 
      set 
      { 
       chargeTimeRemaining_Mins = value; 
       OnPropertyChanged("ChargeTimeRemaining_Mins"); 
      } 
     } 

     #region INotifyPropertyChanged Members 
     public event PropertyChangedEventHandler PropertyChanged; 
     private void OnPropertyChanged(string propertyName) 
     { 
      if (PropertyChanged != null) 
       PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
     #endregion 
    } 
} 

ViewModel:

namespace WpfMVVMApp 
{ 
    public class CountdownViewModel 
    { 
     public CountdownModel Countdown { get; set; } 

     DispatcherTimer timer; 
     private const int maxMins = 360; 

     public CountdownViewModel() 
     { 
      Countdown = new CountdownModel { ChargeTimeRemaining_Mins = 60 }; 

      // Setup timers 
      timer = new DispatcherTimer(); 
      timer.Tick += new EventHandler(this.SystemChargeTimerService); 
      timer.Interval = new TimeSpan(0, 0, 1); 
      timer.Start(); 
     } 

     private void SystemChargeTimerService(object sender, EventArgs e) 
     { 
      //convert to minutes remaining 
      // DEMO CODE - TODO: Remove 
      this.Countdown.ChargeTimeRemaining_Mins -= 1; 
     } 
    } 
} 

Oto XAML za moją kontrolą użytkownika:

<UserControl x:Class="WpfMVVMApp.UserControl1" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="300"> 
    <Grid> 
     <Label Name="Readout"></Label> 
    </Grid> 
</UserControl> 

A oto kod za kontrolą użytkownika:

namespace WpfMVVMApp 
{ 
    public partial class UserControl1 : UserControl 
    { 
     #region Dependency Properties 
     public static readonly DependencyProperty MinutesRemainingProperty = 
        DependencyProperty.Register 
        (
         "MinutesRemaining", typeof(int), typeof(UserControl1), 
         new UIPropertyMetadata(10, new PropertyChangedCallback(minutesRemainChangedCallBack)) 
        ); 
     #endregion 

     public int MinutesRemaining 
     { 
      get 
      { 
       return (int)GetValue(MinutesRemainingProperty); 
      } 
      set 
      { 
       SetValue(MinutesRemainingProperty, value); 
      } 
     } 

     static void minutesRemainChangedCallBack(DependencyObject property, DependencyPropertyChangedEventArgs args) 
     { 
      UserControl1 _readout = (UserControl1)property; 
      _readout.MinutesRemaining = (int)args.NewValue; 

      _readout.Readout.Content = _readout.MinutesRemaining; 
     } 

     public UserControl1() 
     { 
      InitializeComponent(); 
     } 
    } 
} 

Odpowiedz

10

Twoja zmiana zwrotna łamie wiązania.

Jako szkielet: w oknie masz UC.X="{Binding A}", a następnie w tej zmianie właściwości (w UC) masz X=B;. Spowoduje to zerwanie powiązania, ponieważ w obu przypadkach ustawiono X.

Do sprostowania, usunięcia zmiany zwrotnego i dodać do etykiety:

Content="{Binding MinutesRemaining, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}" 
+0

Dziękuję za odpowiedź. Wiązanie to działało. Jednak powodem, dla którego utworzyłem właściwość zależności, jest to, że chcę zrobić coś więcej niż tylko ustawić etykietę w moim rzeczywistym programie (był to tylko prosty przykład). Teraz widzę, że przypisałem wartość do MinutesRemaining w moim wywołaniu zmiany, która zrywa oryginalne powiązanie. Skomentowałem tę linię i teraz działa tak, jak się spodziewałem. – user2367999

2

Próbowałem Twój kod działa poprawnie tylko zmiana zrobiłem było usunąć kod za propertychangedcallback masz i databind etykiety (Odczyt) do właściwości zależności.

usercontrol (XAML)

<UserControl x:Class="WpfApplication1.UserControl" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     mc:Ignorable="d" 
     d:DesignHeight="300" d:DesignWidth="300"> 
    <Grid> 
     <Label Name="Readout" Content="{Binding RelativeSource={RelativeSource 
          AncestorType=UserControl}, Path=MinutesRemaining}"/> 
    </Grid> 
</UserControl> 

usercontrol (KOD ZA)

public partial class UserControl1 : UserControl 
{ 
    #region Dependency Properties 
    public static readonly DependencyProperty MinutesRemainingProperty = 
       DependencyProperty.Register 
       (
        "MinutesRemaining", typeof(int), typeof(UserControl1), 
        new UIPropertyMetadata(10) 
       ); 
    #endregion 

    public int MinutesRemaining 
    { 
     get 
     { 
      return (int)GetValue(MinutesRemainingProperty); 
     } 
     set 
     { 
      SetValue(MinutesRemainingProperty, value); 
     } 
    } 

    public UserControl1() 
    { 
     InitializeComponent(); 
    } 
}