MVVM绑定问题 - 另一个Noob-ish问题

时间:2013-02-05 20:25:30

标签: c# .net wpf data-binding mvvm

所以我又来了,问very similar question to yesterday。我重新考虑了我的项目,以便更好地遵循MVVM模式。现在,我的绑定不再像昨天那样工作了。我试图将停靠面板的可见性绑定到按钮。以下是我的一些代码:

视图模型:

public class SelectWaferButtonViewModel : INotifyPropertyChanged
{
    private bool isClicked;

    public SelectWaferButtonViewModel()
    {
        isClicked = false;
    }

    public bool IsControlVisible
    {
        get
        {
            return isClicked;
        }
        set
        {
            isClicked = value;
            OnPropertyChanged("IsControlVisible");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void OnButtonClick()
    {
        if (isClicked)
        {
            IsControlVisible = false;
        }
        else
        {
            IsControlVisible = true;
        }
    }
    protected virtual void OnPropertyChanged(string property)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(property));
        }
    }
}

XAML:

<Window.Resources>
     <local:BoolToVisibilityConverter x:Key="BoolToVisConverter"/>
     <local:SelectWaferButtonViewModel x:Key="SelectWaferButton" />
     <local:WaferTrackerWindowViewModel x:Key="WindowViewModel" />
</Window.Resources>
<DockPanel
     Name="tvwDockPanel"
     DataContext="{StaticResource SelectWaferButton}"
     Width="225"
     Visibility="{Binding IsControlVisible, Mode=TwoWay, 
                  FallbackValue=Collapsed, 
                  Converter={StaticResource BoolToVisConverter}}"
     DockPanel.Dock="Left">
 </DockPanel>

我的BoolToVisConverter

public class BoolToVisibilityConverter : IValueConverter
{
    public BoolToVisibilityConverter() { }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        bool bValue = (bool) value;
        if (bValue)
        {
            return Visibility.Visible;
        }
        else
        {
            return Visibility.Collapsed;
        }
    }
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        Visibility visibility = (Visibility) value;
        if (visibility == Visibility.Visible)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}

我为一个与昨天类似的问题道歉,但我正在努力解决这个MVVM的问题,因为我对WPF很新。任何帮助将不胜感激。

  • 先谢谢,

编辑: 以下是一些额外的代码段供进一步参考:

public class WaferTrackerWindowViewModel :INotifyPropertyChanged
{
    private SelectWaferButtonViewModel btnSelectWaferViewModel;
    public event PropertyChangedEventHandler PropertyChanged;
    private DelegateCommand exitCommand;
    private DelegateCommand expandPanelCommand;
    private DelegateCommand selectWaferCommand;

    public WaferTrackerWindowViewModel()
    {
        this.InstantiateObjects();
        initThread.RunWorkerAsync();
    }

    public string SelectedWafer
    {
        get
        {
            return selectedWafer;
        }
        set
        {
            selectedWafer = value;
        }
    }
    public ICommand ExitCommand
    {
        get
        {
            if (exitCommand == null)
            {
                exitCommand = new DelegateCommand(Exit);
            }
            return exitCommand;
        }
    }
    public ICommand ExpandPanelCommand
    {
        get
        {
            if (expandPanelCommand == null)
            {
                expandPanelCommand = new DelegateCommand(ExpandPanel);
            }
            return expandPanelCommand;
        }
    }
    public ICommand SelectWaferCommand
    {
        get
        {
            if (selectWaferCommand == null)
            {
                selectWaferCommand = new DelegateCommand(SelectWafer);
            }
            return selectWaferCommand;
        }
    }

    private void InstantiateObjects()
    {
        btnSelectWaferViewModel = new SelectWaferButtonViewModel();
        initThread = new BackgroundWorker();
    }
    private void ExpandPanel()
    {
        btnSelectWaferViewModel.OnButtonClick();
    }
    private void SelectWafer()
    {
       //Does Nothing Yet
    }
    private void Exit()
    {
        Application.Current.Shutdown();
    }
    private void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    private void InitThread_DoWork(object sender, DoWorkEventArgs e)
    {
        TreeViewPresenter tvwPresenter = new TreeViewPresenter();
        tvwPresenter.WaferList = DataLibrary.GetWaferList();
    }
    private void InitThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        tvwPresenter.TreeView.DataContext = tvwPresenter.ProcessesAndWafers;
        tvwPresenter.WaferListCache = tvwPresenter.ProcessesAndWafers;
        tvwPresenter.ProcessArray = tvwPresenter.WaferListCache.ToArray();
    }
}

单击“展开面板”按钮时,它会调用ExpandPanel命令,该命令将执行路由到同一类中的方法“private void ExpandPanel()”。然后,在ExpandPanel()方法中,它调用OnButtonClick()对象上的btnSelectWaferViewModel方法,这将更改IsControlVisible属性。然后,此更改应反映到绑定的停靠面板上,但这不会发生

凯尔

2 个答案:

答案 0 :(得分:2)

(1)ViewModel应位于Window.DataContext部分,而不是Window.Resources部分。

(2)在您的视图模型中,将IsControlVisible属性设为System.Windows.Visibility,而不是布尔值,然后您不需要转换器。

(3)我认为OnButtonClick没有办法解雇,而且确实需要设置ICommand接口。

(4)您不需要实现ConvertBack,因为您绑定的Visibility属性是定义的一种方式。用户无法设置 visibilityfalse

(5)不要混合访问IsClicked及其访问者IsControlVisible。始终在MVVM中使用Accessor,因为您冒着意外设置IsClicked而不会激活OnPropertyChanged的风险。

总而言之,你非常接近。确保密切关注“输出”窗口,它会告诉您绑定是否由于某种原因而失败。但是,挂在那里!

答案 1 :(得分:1)

所以当你这样做时:

<Window.Resources>
    <local:SelectWaferButtonViewModel x:Key="SelectWaferButton" />
</Window.Resources>

WPF将创建SelectWaferButtonViewModel的新实例并将其添加到其资源中。然后通过使用密钥设置DataContext StaticResource来绑定到此。

但是,如果您在后面的代码中创建另一个SelectWaferButtonViewModel并将命令链接到该实例,则它不是同一个实例,因此更改此未绑定实例的属性不会影响您的UI。有几种方法可以解决它。您可以a)在后面的代码中创建一个SelectWaferButtonViewModel作为属性,然后绑定到XAML中的那个,或者b)在当前拥有它的XAML中声明您的SelectWaferButtonViewModel,然后检索该实例在你的代码背后,像这样:

SelectWaferButtonViewModel swbvm = (SelectWaferButtonViewModel)this.FindResource("SelectWaferButton");

修改:因此,在看到您的上一次修改后,如果您想使用a),那么我建议您将btnSelectWaferViewModel作为WaferTrackerWindowViewModel中的属性公开,然后绑定到该属性,并将Window的DataContext设置为WaferTrackerWindowViewModel实例。所以你最终得到的结果是:

<DockPanel
    Name="tvwDockPanel"
    Width="225"
    Visibility="{Binding MyButton.IsControlVisible, 
        Converter={StaticResource BoolToVisConverter}}"
    DockPanel.Dock="Left">
</DockPanel>

public class WaferTrackerWindowViewModel :INotifyPropertyChanged
{
    private SelectWaferButtonViewModel btnSelectWaferViewModel;
    public SelectWaferButtonViewModel MyButton 
    {
        get { return btnSelectWaferViewModel; }
        set
        {
            btnSelectWaferViewModel = value;
            OnPropertyChanged("MyButton");
        }
    }
    //......