所以我又来了,问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
属性。然后,此更改应反映到绑定的停靠面板上,但这不会发生
凯尔
答案 0 :(得分:2)
(1)ViewModel应位于Window.DataContext
部分,而不是Window.Resources
部分。
(2)在您的视图模型中,将IsControlVisible
属性设为System.Windows.Visibility
,而不是布尔值,然后您不需要转换器。
(3)我认为OnButtonClick
没有办法解雇,而且确实需要设置ICommand
接口。
(4)您不需要实现ConvertBack
,因为您绑定的Visibility
属性是定义的一种方式。用户无法设置 visibility
至false
。
(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");
}
}
//......