0

所以我又来了,问了一个与昨天非常相似的问题。我重构了我的项目,以便更好地遵循 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;
        }
    }
}

对于与昨天类似的问题,我深表歉意,但由于我对 WPF 很陌生,因此我正在努力解决这个 MVVM 问题。任何帮助都感激不尽。

  • 提前致谢,

编辑: 这里有一些额外的代码片段供进一步参考:

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属性。然后应该将此更改反映到绑定的停靠面板上,但这不会发生

凯尔

4

2 回答 2

2

(1) ViewModel 应该在Window.DataContextsection,而不是Window.Resourcessection。

(2) 在您的视图模型中,将您的IsControlVisible属性设为 a System.Windows.Visibility,而不是 Boolean,那么您就不需要转换器了。

(3)我看不出有什么方法OnButtonClick可以触发,确实需要设置ICommand界面。

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

(5) 不要混用 accessIsClicked和它的 accessor IsControlVisible。始终在 MVVM 中使用 Accessor,因为您冒着意外设置IsClicked无法激活的风险OnPropertyChanged

总而言之,你已经很接近了。请务必留意您的“输出”窗口,它会告诉您绑定是否由于某种原因失败。但是,是的,坚持住!

于 2013-02-05T20:30:04.483 回答
1

所以当你这样做时:

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

WPF 将创建一个新的实例SelectWaferButtonViewModel并将其添加到它的资源中。DataContext然后,您通过设置使用StaticResourcewith 键来绑定到此。

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

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");
        }
    }
    //......
于 2013-02-05T21:24:43.930 回答