4

カスタムユーザーコントロールの下にネストされたものとして存在する別の要素を参照したいと思います。

<userControls:Test>
     <TextBox Name="Foo" />

     <Button CommandParameter="{Binding Text, ElementName=Foo" Command="{Binding anything}" />
</userControls:Test>

基本的に私はコマンドを使用していて、名前の付いた別の要素を参照しようとしていますが、これは有名になります。

要素'...'にName属性値'...'を設定できません。'...'は要素'...'のスコープ内にあり、別のスコープで定義されたときにすでに名前が登録されています。

要素に名前を付けることは不可能だと思いました:NAMEDコンテンツを使用してWPFUserControlを作成する方法

では、ネストされたカスタムユーザーコントロールコンテンツ内で機能する要素を参照する他の方法はありますか?

4

5 に答える 5

3

あなたの質問に対する直接の答えではありませんが、合理的な回避策です。ビューで、ICommandの宣言のすぐ横にあるビューモデルのTexttoFooTextプロパティをバインドします。コマンドを実行するときは、最新のFooTextを使用してください

<!-- View -->
<userControls:Test>
     <TextBox Text={Binding FooText, Mode=TwoWay} />

     <Button Command="{Binding FooCommand}" />
</userControls:Test>


// ViewModel
public string FooText { get; set; }

public ICommand FooCommand 
{ 
    get 
    { 
        return new DelegateCommand(() => ExecuteFoo(FooText)); 
    } 
} 
于 2012-07-06T15:08:23.813 に答える
1

UserControlのテンプレートを作成してみませんか。

<....Resources>
    <Style TargetType="{x:Type UserControl}" x:Key="MyUserControl">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate>
                    <StackPanel>
                        <TextBox x:Name="PART_Foo"/>
                        <TextBlock Text="{Binding ElementName=PART_Foo, Path=Text}"/>
                        <ContentPresenter  Content="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},Path=Content}"/>
                    </StackPanel>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</....Resources>
<UserControl Style="{StaticResource MyUserControl}">
</UserControl>

次に、キーを使用してテンプレートに名前を付け、どのUserControlがどのテンプレートを使用するかを指定します。

また、コードでは、次を使用してテンプレート化されたパーツのPART_Nameを取得できます。

UIElement GetUserControlPart(UserControl control, String name)
{
   return control.Template.FindName(name, control) as UIElement;
}
于 2012-07-06T16:34:52.913 に答える
1

私はこのようにそれをすることになった:

<UserControl x:Class="MyProject.FooBar"
         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:userControls="clr-namespace:MyProject.UserControls"
         Loaded="Loaded"> <!-- notice -->

    <userControls:Test>
         <TextBox Initialized="FooInitialized" />

         <Button Initialized="AnotherInitialized" />
    </userControls:Test>

そしてコード:

// This for every initialization, all we do is set names after the elements are initialized.
private void FooInitialized(object sender, EventArgs e)
{
    ((TextBox) sender).Name = "Foo";
}

// Here when the entire junk is loaded, we set the necessary commands.
private void Loaded(object sender, EventArgs e)
{
    // Find elements.
    var button = UIHelper.FindChild<Button>(this, "Bar");
    var textBox = UIHelper.FindChild<TextBox>(this, "Foo");

    // Set up bindings for button.
    button.Command = ((FooViewModel) DataContext).FooCommand;
    button.CommandParameter = textBox;
}

これUIHelperhttps://stackoverflow.com/a/1759923/283055からのものです。ボタンにも、テキストボックスと同じ方法で名前が付けられます。

基本的にすべての名前はInitializedイベントを介して設定されます。唯一の欠点は、コードで名前を参照する必要があることです。そのため、コンポーネント全体がロードされた後、コードを介してコマンドを設定しています。これがコードとUIマークアップの間の最良の妥協点であることがわかりました。

于 2012-07-09T12:20:07.187 に答える
0

.NET 4.0を使用していて、バインディングソースを兄弟コントロールに設定する必要がある場合は、次のMarkupExtensionを使用できます。

public class SiblingSourceBinding : MarkupExtension
{  
    public Binding Binding
    {
        get;
        set;
    }

    public int SiblingIndex
    {
        get;
        set;
    }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        var provideValueTarget = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;

        if (provideValueTarget != null)
            this.Binding.Source = LogicalTreeHelper.GetChildren(LogicalTreeHelper.GetParent(provideValueTarget.TargetObject as DependencyObject)).Cast<object>().ElementAt(this.SiblingIndex);
        else
            throw new InvalidOperationException("Unable to set sibling binding source.");

        return this.Binding.ProvideValue(serviceProvider);
   }

次のように使用します。

<userControls:Test>
    <TextBox/>
    <Button CommandParameter="{local:SiblingSourceBinding Binding={Binding Text}, SiblingIndex=0}" Command="{Binding anything}"/>
</userControls:Test>
于 2012-07-06T16:20:21.107 に答える
0

次のように、ネストされた要素でUidを使用できます。

<userControls:Test Name="usrCtrl">
     <TextBox Uid="Foo" />
     <Button Uid="btn"/>
</userControls:Test>

次に、次の関数を使用します(この関数は、この回答の解決策でした。WPFのUidでオブジェクトを取得します)。

private static UIElement FindUid(this DependencyObject parent, string uid)
{
    var count = VisualTreeHelper.GetChildrenCount(parent);
    if (count == 0) return null;

    for (int i = 0; i < count; i++)
    {
        var el = VisualTreeHelper.GetChild(parent, i) as UIElement;
        if (el == null) continue;

        if (el.Uid == uid) return el;

        el = el.FindUid(uid);
        if (el != null) return el;
    }
    return null;
}

次に、Loaded関数に次を追加します。

private void Loaded(object sender, EventArgs e)
{
    // Find elements.
    var button = FindUid(usrCtrl, "btn") as Button;
    var textBox = FindUid(usrCtrl, "Foo") as TextBox;
     
    // Do binding here...
}
于 2020-10-21T07:13:59.853 に答える