我尝试使用datagrid构建基于wpf的应用程序,并将itemsource绑定到一个对象。
的Xaml
<DataGrid ItemsSource="{Binding Folders, Mode=TwoWay}" AutoGenerateColumns="False" HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Path" CanUserResize="False">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="260"></ColumnDefinition>
<ColumnDefinition Width="30"></ColumnDefinition>
<ColumnDefinition Width="30"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" Text="{Binding Path}">
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Cursor" Value="Arrow"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
和生成的源代码
public partial class FolderControl : UserControl
{
public FolderViewModel FolderViewModel = new FolderViewModel("SourceFolders.xml");
public FolderControl()
{
InitializeComponent();
DataContext = FolderViewModel;
}
private TextBox GetTextBoxInstance(object obj)
{
var btn = (Button) obj;
var parent = (Grid) btn.Parent;
var text = (TextBox) parent.Children.Cast<UIElement>().Select(tb => tb).First();
return text;
}
private void OpenFolder_OnClick(object sender, RoutedEventArgs e)
{
var text = GetTextBoxInstance(sender);
Win32.FolderBrowserDialog fbd = new Win32.FolderBrowserDialog();
Win32.DialogResult showDialog = fbd.ShowDialog();
text.Text = fbd.SelectedPath;
}
private void OpenFile_OnClick(object sender, RoutedEventArgs e)
{
var text = GetTextBoxInstance(sender);
Win32.OpenFileDialog ofd = new Win32.OpenFileDialog();
if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
// If find the same file on collection, show msg error
if (FolderViewModel.Folders.Any(file => file.Path == ofd.FileName))
{
MessageBoxResult result = MessageBox.Show(EN.TEXT4, "Info", MessageBoxButton.OK);
}
else
{
text.Text = ofd.FileName;
}
}
}
}
和viewModel(我不会在这里显示整个代码,只是必要的内容)
public class FolderViewModel : UploadViewModelBase
{
public BindingList<Folder> Folders { get; set; }
public FolderViewModel(string filename)
: base(filename)
{
}
这里我使用bindinglist泛型类型集合而不是observecollection来观察集合的变化 最后一个文件是模型
public class Folder : ObservableObject
{
private String _path;
private OsType _os;
private String _strOs;
public String Path
{
get { return _path; }
set { _path = value; RaisePropertyChanged(() => this.Path); }
}
public OsType Os
{
get { return _os; }
set { _os = value; RaisePropertyChanged(() => this.Os); }
}
public String StrOs
{
get { return _strOs; }
set { _strOs = value; RaisePropertyChanged(() => this.StrOs); }
}
}
整个问题就在这里,当我从一行更改内容时,它不会在集合对象上发生变化。我做错了什么?
答案 0 :(得分:1)
您对数据绑定感到困惑。以下是一些提示:
Two-Way Binding
用于显示的控件,可以编辑数据绑定值,而不是容器控件的属性......这意味着没有任何意义在Mode="Two-Way"
媒体资源上设置ItemsSource
,因为如果你查看MSDN上的ItemsControl.ItemsSource
Property页面,就会发现它只支持One-Way Binding
s。
如上所述,设置Mode="Two-Way"
只应用于可显示并可编辑数据绑定值的控件。但是,如果您查看MSDN上的TextBox.Text
property页面,您应该会看到名为依赖项属性信息的部分。在本节中,您可以看到默认情况下Textbox.Text
属性绑定Two-Way
,因此您永远不必对其应用该设置。
所以,虽然你说你的解决方案是使用以下内容:
<TextBox Grid.Column="0" Text="{Binding Path, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" ... />
我相当确定它只是您需要设置的UpdateSourceTrigger
属性,因为我们现在都知道,在Mode=TwoWay
属性上设置Textbox.Text
不会做任何事情:
<TextBox Grid.Column="0" Text="{Binding Path, UpdateSourceTrigger=PropertyChanged}" ... />
答案 1 :(得分:0)
我的代码中至少可以看到以下两个问题:
DataGrid
永远不会修改ItemsSource
引用本身(仅限其&#34;内容&#34;),因此您不应设置Mode=TwoWay
。BindingList<T>
未实现此接口。因此,您最好使用ObservableCollection<T>
来实现此接口。此外,
public BindingList Folders { get; set; }
似乎不正确,如果您的BindingList
就是这个:MSDN documentation for BindingList。它应该是
public BindingList<Folder> Folders { get; set; }
但也许这只是你问题上的一个错字。