![](/img/trans.png)
[英]Howto bind Views to Viewmodel in a MVVM-Environment with XAML and WPF in C#
[英]Bind WPF Command to ViewModel property in C# XAML
我正在尝试构建一个通用Command
,该Command
可以从ViewModel
访问属性。 在我的窗口上有几个TextBoxes
,每个TextBox
旁边都有一个Button
。 当Button
被点击我表现出OpenFileDialog
和设置Text
中的TextBox
到选定的文件路径。 TextBox
本身具有对ViewModel
的属性的Binding
。 当前,这是通过ViewModel
的Command
实现的。 Buttons
都调用相同的Command
但是每个Button
的属性CommandParameter
设置为TextBox
,它将接收文件路径。 这样做的缺点是,我需要将Command
执行中的参数强制转换为TextBox
,然后设置其Text
属性。 现在的问题是,如果我不能以某种方式将“命令”绑定到TextBox
绑定到的同一属性。 这是我目前正在做的事情:
XAML
<TextBox Text="{Binding SettingsPath}" x:Name="txtSettingsPath"></TextBox>
<Button Command="{Binding OpenFile}"
CommandParameter="{Binding ElementName=txtSettingsPath}">...</Button>
C#
public ICommand OpenFile
{
get
{
bool CanExecuteOpenFileCommand()
{
return true;
}
CommandHandler GetOpenFileCommand()
{
return new CommandHandler((o) =>
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Multiselect = false;
if (!string.IsNullOrEmpty(SettingsPath) && File.Exists(settingsPath))
{
ofd.InitialDirectory = Path.GetDirectoryName(SettingsPath);
}
if(ofd.ShowDialog() == true)
{
if(o is TextBox txt)
{
txt.Text = ofd.FileName;
}
}
}, CanExecuteOpenFileCommand);
}
return GetOpenFileCommand();
}
}
在XAML中,我想要这样的东西:
<TextBox Text="{Binding SettingsPath}"></TextBox>
<Button Command="{Binding OpenFile}"
CommandParameter="{Binding SettingsPath}">...</Button>
这是我在评论中谈论的内容:
“小视图模型”。 我添加了Label
属性,因为在我的测试项目中,它们看起来都一样。 那不一定是这个视图模型的一部分。
public class SettingsPathSelectorViewModel : ViewModelBase
{
#region Label Property
private String _label = default(String);
public String Label
{
get { return _label; }
set
{
if (value != _label)
{
_label = value;
OnPropertyChanged();
}
}
}
#endregion Label Property
#region SettingsPath Property
private String _settingsPath = null;
public String SettingsPath
{
get { return _settingsPath; }
set
{
if (value != _settingsPath)
{
_settingsPath = value;
OnPropertyChanged();
}
}
}
#endregion SettingsPath Property
public ICommand OpenFile
{
get
{
bool CanExecuteOpenFileCommand()
{
return true;
}
// We're no longer using the parameter, since we now have one
// command per SettingsPath.
CommandHandler GetOpenFileCommand()
{
return new CommandHandler((o) =>
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Multiselect = false;
if (!string.IsNullOrEmpty(SettingsPath) && System.IO.File.Exists(SettingsPath))
{
ofd.InitialDirectory = System.IO.Path.GetDirectoryName(SettingsPath);
}
if (ofd.ShowDialog() == true)
{
SettingsPath = ofd.FileName;
}
}, o => CanExecuteOpenFileCommand());
}
return GetOpenFileCommand();
}
}
}
用于演示目的的快速主视图模型。 我们将说明两种公开这些内容的方法:作为命名属性,或在ItemsControl
显示的各种大小的集合。
public class MainViewModel : ViewModelBase
{
public SettingsPathSelectorViewModel FirstPath { get; } = new SettingsPathSelectorViewModel() { Label = "First Path" };
public SettingsPathSelectorViewModel SecondPath { get; } = new SettingsPathSelectorViewModel() { Label = "Second Path" };
public ObservableCollection<SettingsPathSelectorViewModel> SettingsPaths { get; } = new ObservableCollection<SettingsPathSelectorViewModel>
{
new SettingsPathSelectorViewModel() { Label = "First Collection Path" },
new SettingsPathSelectorViewModel() { Label = "Second Collection Path" },
new SettingsPathSelectorViewModel() { Label = "Third Collection Path" },
};
}
XAML:
<Window.Resources>
<DataTemplate DataType="{x:Type local:SettingsPathSelectorViewModel}">
<!-- GroupBox and Label are optional -->
<GroupBox Header="{Binding Label}">
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding SettingsPath}" />
<Button
Content="..."
Command="{Binding OpenFile}"
HorizontalAlignment="Left"
MinWidth="40"
Margin="4,0,0,0"
/>
</StackPanel>
</GroupBox>
</DataTemplate>
</Window.Resources>
<Grid>
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<ContentControl Content="{Binding FirstPath}" />
<ContentControl Content="{Binding SecondPath}" />
</StackPanel>
<ItemsControl
ItemsSource="{Binding SettingsPaths}"
/>
</StackPanel>
</Grid>
这就是我省略Label
和GroupBox
:
<Window.Resources>
<DataTemplate DataType="{x:Type local:SettingsPathSelectorViewModel}">
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding SettingsPath}" />
<Button
Content="..."
Command="{Binding OpenFile}"
HorizontalAlignment="Left"
MinWidth="40"
Margin="4,0,0,0"
/>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<StackPanel Orientation="Vertical">
<Label>First Path</Label>
<ContentControl Content="{Binding FirstPath}" />
<Label>Second Path</Label>
<ContentControl Content="{Binding SecondPath}" />
</StackPanel>
</Grid>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.