WPF MVVM: Strange Binding behavior

北慕城南 提交于 2019-12-12 03:28:10

问题


I have a UserControl that contains a TabControl.

<UserControl x:Class="Test.MyUC"
....
         xmlns:vm="clr-namespace:Test.ViewModels"
         xmlns:ikriv="clr-namespace:IKriv.Windows.Controls.Behaviors"

...

<UserControl.Resources>
    <vm:MyUCVM x:Key="VM" />
</UserControl.Resources>

<UserControl.DataContext>
    <StaticResourceExtension ResourceKey="VM" />
</UserControl.DataContext>

<!-- Using Ivan Krivyakov's Attached Behavior -->
<TabControl ikriv:TabContent.IsCached="True"
            TabStripPlacement="Top" ItemsSource="{Binding TabList}" IsSynchronizedWithCurrentItem="True">
    <TabControl.Resources>
        <DataTemplate DataType="{x:Type vm:MyTab1VM}">
            <v:MyTab1/>
        </DataTemplate>
        <DataTemplate DataType="{x:Type vm:MyTab2VM}">
            <v:MyTab2/>
        </DataTemplate>
    </TabControl.Resources>
...

Of course, in MyUCVM, I have TabList. Now, up to this point, everything works fine.

The problem starts when one of the tabs (e.g. MyTab1) in the TabControl needs to continuously and recursively read data from some external source (done in the ViewModel of course), and pass that data to View (via Binding) to display. Even up to this point everything is working. However, I do not want that to run when the tab is not visible, because there is no point to do that.

To do that, MyTab1VM needs to know if the associated View (MyTab1) is the selected tab. Therefore, I wired this up:

MyTab1:
<Style TargetType="TabItem">
    <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=OneWayToSource}" />
</Style>

MyTab1VM
public static readonly DependencyProperty IsSelectedProperty =
    DependencyProperty.Register("IsSelected",
    typeof(bool),
    typeof(MyTab1VM),
    new PropertyMetadata(false, new PropertyChangedCallback(IsSelectedChanged))
    );

public bool IsSelected
{
    get
    {
        return (bool) GetValue(IsSelectedProperty);
    }
    set
    {
        SetValue(IsSelectedProperty, value);
    }
}
public static void IsSelectedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    if (e.Property == IsSelectedProperty)
    {
        MyTab1VM vm = d as MyTab1VM ;

        vm.SetupToGetData();
    }
}
private void SetupToGetData()
{
    if (this.IsSelected)
    {
        System.Windows.Threading.DispatcherTimer timer = new System.Windows.Threading.DispatcherTimer();
        timer.Interval = TimeSpan.FromMilliseconds(100);
        timer.Tick += timer_Tick;
        timer.Start();
    }
}
private void timer_Tick(object sender, EventArgs e)
{
    if (this.IsSelected)
        this.MyData = ExternalSource.GetData();
    else
    {
        (sender as System.Windows.Threading.DispatcherTimer).Stop();
    }
}

Unfortunately, this setup only works when I set this.IsSelected = true; manually in the MyTab1VM's constructor. Leaving that out in the constructor, the data do not get shown in the view.

I have set breakpoints and confirmed that the binding for IsSelected is running correctly. Even the timer is running, and ExternalSource.GetData() is being called. But this.MyData = ExternalSource.GetData(); is not triggering the change from the ViewModel to the View.

The most puzzling part is that the same binding is triggered if IsSelected is set to true from the constructor.

Anyone out there knows what happened here?


回答1:


I managed to do some fruitful troubleshooting on my own. I made a breakpoint in SetupToGetData() and I put this.GetHashCode() in my debugging watchlist. When I manually set this.IsSelected = true in the constructor, I realized that the SetupToGetData() method is called twice, with two different hash values. Planting another breakpoint in the constructor also showed that the constructor is called when I switch to this tab.

I have decided to move this to a new question, because it looks highly possible that the problem has nothing to do with binding.

Edit

Seems like I was right that this is the root of this problem. As that question is solved, so is this as well.



来源:https://stackoverflow.com/questions/37068521/wpf-mvvm-strange-binding-behavior

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!