简体   繁体   English

WPF使用ContentPresenters和UserControl“找不到绑定源”

[英]WPF “Cannot find source for binding” with ContentPresenters, and UserControl

I have a: 我有一个:

System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=Test'. System.Windows.Data错误:4:找不到参考'ElementName = Test'的绑定源。 BindingExpression:Path=Value; BindingExpression:Path = Value; DataItem=null; DataItem = null; target element is 'Slider' (Name=''); 目标元素是'Slider'(Name =''); target property is 'Value' (type 'Double') 目标属性为“值”(类型为“双精度”)

error in a very special case. 在非常特殊的情况下出错。 I though about a name scope problem but I don't know how to fix it. 我虽然遇到名称范围问题,但不知道如何解决。

Consider the following WPF application : 考虑以下WPF应用程序:

MyUserControl.xaml : MyUserControl.xaml

<UserControl x:Class="WpfApplication1.MyUserControl"
             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" mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <Label Grid.Row="0" Content="Move me !"/>
        <Slider x:Name="Test" Grid.Row="0" Grid.Column="1" />
        <Label Grid.Row="1" Content="Binded slider"/>
        <ContentPresenter Grid.Row="1" Grid.Column="1">
            <ContentPresenter.Content>
                <Slider Value="{Binding Value, ElementName=Test}"/>
            </ContentPresenter.Content>
        </ContentPresenter>
    </Grid>
</UserControl>

MyUserControl.xaml.cs : MyUserControl.xaml.cs

using System.Windows.Controls;

namespace WpfApplication1
{
    public partial class MyUserControl : UserControl
    {
        public MyUserControl()
        {
            InitializeComponent();
        }
    }
}

MainWindow.xaml : MainWindow.xaml

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Width="300" Height="120">

    <StackPanel>
        <Button Click="Button_Click" Content="Click me to show Sliders !" Height="25"/>
        <ContentPresenter x:Name="contentPresenter"/>
    </StackPanel>
</Window>

MainWindow.xaml.cs : MainWindow.xaml.cs

using System.Windows;

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {
        private MyUserControl myUserControl;

        public MainWindow()
        {
            InitializeComponent();

            myUserControl = new MyUserControl();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            contentPresenter.Content = myUserControl;
        }
    }
}

Given the code of MyUserControl.xaml, I expect the binded slider to have the same value has the first one. 给定MyUserControl.xaml的代码,我希望绑定滑块具有与第一个相同的值。

But nothing happens. 但是什么也没发生。

Now, the tricky part: Start the application, Click on the button, Move the first slider, Open "WPF Inspector" and Attach it to the application. 现在,棘手的部分是:启动应用程序,单击按钮,移动第一个滑块,打开“ WPF Inspector”并将其附加到应用程序。 Result: The binding is fixed. 结果:绑定是固定的。

How do you explain this phenomenon? 您如何解释这种现象?

This will do the trick 这将解决问题

    <!--<ContentPresenter Grid.Row="1" Grid.Column="1">
        <ContentPresenter.Content>-->
            <Slider Value="{Binding Value, ElementName=Test}" Grid.Column="1" Grid.Row="1"/>
        <!--</ContentPresenter.Content>
    </ContentPresenter>-->

Because Slider is inside a content presenter you can't access it's value like that. 由于Slider位于内容演示者内部,因此您无法访问它的值。 You would need to bind to the same viewmodel property to achive this while having it in the content presenter. 您需要将其绑定到相同的viewmodel属性,同时将其放入内容演示器中。

Edit 编辑

Get Prism and user a ViewModel... I won't go into details... But What you need to do is this... 获取Prism并为用户提供ViewModel ...我不会详细介绍...但是您需要做的是...

After you donwloaded everything add the Microsoft.Practices.Prism dll to your project 卸载所有内容后,将Microsoft.Practices.Prism dll添加到项目中

Create a new class (ViewModel).Name it whatever you want. 创建一个新类(ViewModel),并根据需要命名。 I call my MyUserControlViewModel and make it look like this 我叫MyUserControlViewModel ,使它看起来像这样

using Microsoft.Practices.Prism.ViewModel;

namespace YourNamespace
{
    public class MyUserControlViewModel : NotificationObject
    {
        private double _sliderValue;

        public double SliderValue
        {
            get { return _sliderValue; }
            set
            {
                _sliderValue = value;
                RaisePropertyChanged(() => SliderValue);
            }
        }

    }
}

Change the XAML in your usercontrol like this 像这样在用户控件中更改XAML

<Slider x:Name="Test" Grid.Row="0" Grid.Column="1" Value="{Binding SliderValue, Mode=TwoWay}"/>        
<ContentPresenter Grid.Row="1" Grid.Column="1">
    <ContentPresenter.Content>
        <Slider Value="{Binding SliderValue}"/>
    </ContentPresenter.Content>
</ContentPresenter>

And add this line of code into your MyUserControl.cs file 并将这行代码添加到MyUserControl.cs文件中

DataContext = new MyUserControlViewModel();

Now the ViewModel takes over for the heavy lifting... You bound the value of the first slider to the Property SliderValue (the Mode=TwoWay indicates that this control can set and get the state of the property) and you have bound the other slider to the same SliderValue so that it moves in sync with the first 现在,ViewModel接管了繁重的工作……将第一个滑块的值绑定到Property SliderValueMode=TwoWay表示此控件可以设置并获取属性的状态),并且绑定了另一个滑块到相同的SliderValue以便它与第一个同步

Hope this helps 希望这可以帮助

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM