我环顾四周但仍无法找到解决方案...
我创建了一个UserControl
,它基本上是一个滑块,但几乎没有自定义功能。
public partial class CustomSlider : UserControl
{
public CustomSlider()
{
InitializeComponent();
this.DataContext = this;
CMiXSlider.ApplyTemplate();
Thumb thumb0 = (CMiXSlider.Template.FindName("PART_Track", CMiXSlider) as Track).Thumb;
thumb0.MouseEnter += new MouseEventHandler(thumb_MouseEnter);
}
private void thumb_MouseEnter(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed && e.MouseDevice.Captured == null)
{
MouseButtonEventArgs args = new MouseButtonEventArgs(e.MouseDevice, e.Timestamp, MouseButton.Left);
args.RoutedEvent = MouseLeftButtonDownEvent;
(sender as Thumb).RaiseEvent(args);
}
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(double), typeof(CustomSlider), new PropertyMetadata(0.0));
public double Value
{
get { return (double)this.GetValue(ValueProperty); }
set { this.SetValue(ValueProperty, value); }
}
}
XAML:
<UserControl x:Class="CMiX.CustomSlider"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:CMiX"
mc:Ignorable="d"
d:DesignHeight="139.8" d:DesignWidth="546.2">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/CMiX_UserControl;component/RessourceDictionnaries/Brushes/GenericBrushes.xaml"/>
<ResourceDictionary Source="/CMiX_UserControl;component/RessourceDictionnaries/Styles/BaseSliderStyle.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Slider x:Name="CMiXSlider" Style="{StaticResource BaseSliderStyle}"
Value="{Binding Value, Mode=TwoWay, RelativeSource={RelativeSource AncestorType={x:Type local:CustomSlider}}}"
IsMoveToPointEnabled="True" Minimum="0.0" Maximum="1.0"/>
</Grid>
然后我在另一个UserControl
内使用它:
<CMiX:CustomSlider x:Name="SliderTest" Grid.Row="2" Value="{Binding ChannelsAlpha[0], Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
我正在尝试绑定到此ObservableCollection
(相同的滑块将被使用6次):
private ObservableCollection<double> _ChannelsAlpha = new ObservableCollection<double>(new[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 });
public ObservableCollection<double> ChannelsAlpha
{
get { return _ChannelsAlpha; }
set { _ChannelsAlpha = value; }
}
问题是,绑定不会以任何方式发生。而我特别不知道的是,如果我使用这个标准滑块:
<Slider x:Name="Ch0_Alpha" Margin="1" IsMoveToPointEnabled="True" Minimum="0.0" Maximum="1.0" Orientation="Horizontal" Value="{Binding DataContext.ChannelsAlpha[0], ElementName=Ch0_Alpha, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
然后它按预期工作。
答案 0 :(得分:3)
您无法绑定任何内容,因为您非常小心地破坏了DataContext:
this.DataContext = this;
不要这样做。要绑定到UserControl本身的属性,请使用RelativeSource绑定,例如......与您已使用的绑定完全相同:
<Slider
x:Name="CMiXSlider"
Style="{StaticResource BaseSliderStyle}"
Value="{Binding Value, Mode=TwoWay, RelativeSource={RelativeSource AncestorType={x:Type local:CustomSlider}}}"
IsMoveToPointEnabled="True"
Minimum="0.0"
Maximum="1.0"
/>
我没有看到你在UserControl XAML中使用DataContext的任何地方,所以我只是在构造函数中删除该行并去喝啤酒。
嗯,首先,为了良好的形式,我将摆脱构造函数中的模板内容,并将其移至OnApplyTemplate:
public CustomSlider()
{
InitializeComponent();
}
public override void OnApplyTemplate()
{
Thumb thumb0 = (CMiXSlider.Template.FindName("PART_Track", CMiXSlider) as Track).Thumb;
thumb0.MouseEnter += new MouseEventHandler(thumb_MouseEnter);
}
然后是啤酒。
P.S。以下是如何调试绑定:
Value="{Binding ChannelsAlpha[0], PresentationTraceSources.TraceMode=High, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
添加PresentationTraceSources.TraceMode=High
,然后在运行时观看VS中的“输出”窗口。它将告诉您尝试解决绑定所需的所有步骤。它在这种情况下告诉你的是,它在ChannelIsAlpha
的实例上寻找CMiX:CustomSlider
而不是在viewmodel上。这就是你的线索,即通过摆脱DataContext
的继承值来创建问题。在构造函数中,this.DataContext
是父视图的viewmodel,直到您将其设置为this
(在断点中弹出并查看)。
这就是为什么我们这些胡思乱想的老人有这样一个关于不设置this.DataContext = this;
的毛刺的原因。首先,如果它是相对无害的,那么你开始认为它只是必要的样板,而你就是这样。事实上,它永远不会必要。
Bindings和DataContext
很难习惯,因为这种隐含的事情正在发生。起初我觉得很奇怪。请记住,默认情况下,所有绑定都希望绑定到viewmodel,并且您应始终能够假设无论身在何处,DataContext
都将成为viewmodel。永远不要明确地设置DataContext
。
绑定到除viewmodel之外的任何内容都是一种特殊情况:RelativeSource={RelativeSource AncestorType=FooBar}
,Source={StaticResource WhateverKey}
,ElementName=FooBarListBox
,RelativeSource={RelativeSource Self}
或其他。