1 回答
TA贡献1951条经验 获得超3个赞
这里有太多错误,向您展示正确的代码比解释所有内容更容易。阅读我上面链接的文章并研究这段代码。我还没有完全按照我的方式重新设计:例如,没有主视图模型。现在这不是 MVVM 的一个很好的示例,但它说明了您在网格中放置了哪些内容、如何编写模板列以及如何正确更新属性。
首先,您使用用户控件的实例作为同一控件的视图模型,但它并不是真正的视图模型,因为它从不引发任何属性更改通知。让我们为网格编写一个实际的项目视图模型。这不是 UI 控件。它是数据,将显示在UI 控件中。它拥有信息,并且当信息发生变化时它会收到通知。如果你愿意的话,它也可以有一些逻辑。
public class SliderItem : ObservableObject
{
public SliderItem()
{
}
public SliderItem(int trans, int rot, int scale)
{
Translation = trans;
Rotation = rot;
Scale = scale;
}
public void UpdateValues(int newTrans, int newRot, int newScale)
{
Translation = newTrans;
Rotation = newRot;
Scale = newScale;
}
public void UpdateDescription(string newText)
{
if(!String.IsNullOrWhiteSpace(newText))
{
Description = newText;
OnPropertyChanged(nameof(Description));
}
}
public String Description { get; private set; }
private int _translation = 0;
public int Translation
{
get { return _translation; }
set
{
if (value != _translation)
{
_translation = value;
OnPropertyChanged(nameof(Translation));
}
}
}
private int _rotation = 0;
public int Rotation
{
get { return _rotation; }
set
{
if (value != _rotation)
{
_rotation = value;
OnPropertyChanged(nameof(Rotation));
}
}
}
private int _scale = 0;
public int Scale
{
get { return _scale; }
set
{
if (value != _scale)
{
_scale = value;
OnPropertyChanged(nameof(Scale));
}
}
}
}
TripleSlider.xaml
TripleSlider 的 XAML 基本上没问题;主要问题是它正在寻找以前不存在的视图模型。但我们还希望滑块值绑定在Value更改时更新绑定属性,而不是在滑块控件失去焦点时(这是不明显的默认行为)。因此,添加UpdateSourceTrigger=PropertyChanged到所有三个 Slider.Value 绑定。
Value="{Binding Path=Translation, UpdateSourceTrigger=PropertyChanged}"
TripleSlider.xaml.cs
就是这个。这就是该类应该的样子。
public partial class TripleSlider : UserControl
{
public TripleSlider()
{
InitializeComponent();
}
}
MainWindow.xaml 没问题。MainWindow.xaml.cs 做了一些更改:
public partial class MainWindow : Window
{
// Don't use arrays. Use ObservableCollection<WhateverClass> for binding to UI controls,
// use List<Whatever> for anything else.
private ObservableCollection<SliderItem> _sliders = new ObservableCollection<SliderItem>();
public MainWindow()
{
InitializeComponent();
// The ObservableCollection will notify the grid when you add or remove items
// from the collection. Set this and forget it. Everywhere else, interact with
// _sliders, and let the DataGrid handle its end by itself.
// Also get rid of EnableRowVirtualization="False" from the DataGrid. Let it
// virtualize.
myDataGrid.ItemsSource = _sliders;
}
private void BAddControls_Click(object sender, RoutedEventArgs e)
{
for (int i = 0; i < 49; i++)
{
var newSlider = new SliderItem();
newSlider.UpdateDescription(String.Format("{0}: Unkown Value", (i+1)));
newSlider.UpdateValues((i+1)*1337, (i+1)*1337, (i+1)*1337);
_sliders.Add(newSlider);
}
bAddControls.IsEnabled = false;
}
private void BFetchValues_Click(object sender, RoutedEventArgs e)
{
if (myDataGrid.SelectedItem != null)
{
var selectedSlider = myDataGrid.SelectedItem as SliderItem;
MessageBox.Show(String.Format("Translation: {0}\nRotation: {1}\nScale: {2}", selectedSlider.Translation, selectedSlider.Rotation, selectedSlider.Scale), "Information", MessageBoxButton.OK, MessageBoxImage.Information);
}
}
private void MyDataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
bFetchValues.IsEnabled = (myDataGrid.SelectedItem != null) ? true : false;
}
}
- 1 回答
- 0 关注
- 86 浏览
添加回答
举报