WPF UserControl DependencyProperty использовать в XAML или связыванием - PullRequest
0 голосов
/ 01 июля 2018

Мне нужен универсальный UserControl, в котором я могу установить свойство, либо установив его значение в XAML напрямую, либо связав его с некоторым свойством модели.

Так же, как TextBlock, свойство Text работает.

Прямо сейчас у меня есть простой простой UserControl, у него есть одно свойство DependencyProperty TxT и привязанное к нему свойство TextBlock Text. Никакого другого кода нет.

Если я установлю TxT в XAML в главном окне, это не сработает, привязка сработает.

Если я добавлю PropertyChangedCallback к этому DependencyProperty, он также будет работать в XAML.

Итак, вопрос, обязательно ли иметь PropertyChangedCallback для каждого свойства, если я хочу иметь возможность установить его непосредственно в XAML?

Это неясно для меня, большинство не упоминают об этом, но это также вынуждает меня добавлять имена внутренних элементов управления для изменения их значения в PropertyChangedCallback.

Код ниже.

Можно ли это сделать другим способом?

MainWindow

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:WpfAppDpBare" xmlns:Model="clr-namespace:WpfAppDpBare.Model" x:Class="WpfAppDpBare.MainWindow"
    Background="CadetBlue"
    mc:Ignorable="d"
    Title="MainWindow" Height="450" Width="800" ResizeMode="NoResize" WindowStartupLocation="CenterScreen">
<Window.DataContext>
    <Model:MainModel/>
</Window.DataContext>
<Grid>
    <local:UserControlSample TxT="DIRECT TXT" HorizontalAlignment="Center" VerticalAlignment="Center" Height="125" Width="125" Margin="10,34,659,262"/>
    <TextBlock HorizontalAlignment="Left" Margin="10,10,0,0" TextWrapping="Wrap" Text="Direct" VerticalAlignment="Top" FontSize="14" FontWeight="Bold"/>
    <TextBlock HorizontalAlignment="Left" Margin="203,10,0,0" TextWrapping="Wrap" Text="Binding" VerticalAlignment="Top" FontSize="14" FontWeight="Bold"/>
    <local:UserControlSample DataContext="{Binding UCData}" HorizontalAlignment="Center" VerticalAlignment="Center" Height="125" Width="125" Margin="203,34,466,262"/>
</Grid>

public partial class MainWindow:Window {
    public MainWindow() {
        InitializeComponent();
        }
    }

UserControl

<UserControl x:Class="WpfAppDpBare.UserControlSample"
         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:WpfAppDpBare"
         mc:Ignorable="d" 
         d:DesignHeight="450" d:DesignWidth="800" Background="White">
<Grid>
    <TextBlock TextWrapping="Wrap" Text="{Binding TxT,FallbackValue=...,TargetNullValue=...}" TextAlignment="Center" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="20" FontWeight="Bold"/>

</Grid>

 public partial class UserControlSample:UserControl {
    public UserControlSample() {
        InitializeComponent();
        }

    public string TxT {
        get { return (string)GetValue(TxTProperty); }
        set { SetValue(TxTProperty, value); }
        }

    // Using a DependencyProperty as the backing store for TxT.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty TxTProperty =
        DependencyProperty.Register("TxT", typeof(string), typeof(UserControlSample), new PropertyMetadata());

    }

Модель

  public class MainModel:ViewModelBase {

    /// <summary>
    /// The <see cref="UCData" /> property's name.
    /// </summary>
    public const string UCDataPropertyName = "UCData";

    private UCModel uCModel = null;

    /// <summary>
    /// Sets and gets the UCData property.
    /// Changes to that property's value raise the PropertyChanged event. 
    /// </summary>
    public UCModel UCData {
        get {
            return uCModel;
            }

        set {
            if(uCModel == value) {
                return;
                }

            uCModel = value;
            RaisePropertyChanged(UCDataPropertyName);
            }
        }

    public MainModel() {
        UCData = new UCModel() { TxT = "BINDING TXT" };
        }

    }

public class UCModel:ViewModelBase {

    /// <summary>
    /// The <see cref="TxT" /> property's name.
    /// </summary>
    public const string TxTPropertyName = "TxT";

    private string _TxT = null;

    /// <summary>
    /// Sets and gets the TxT property.
    /// Changes to that property's value raise the PropertyChanged event. 
    /// </summary>
    public string TxT {
        get {
            return _TxT;
            }

        set {
            if(_TxT == value) {
                return;
                }

            _TxT = value;
            RaisePropertyChanged(TxTPropertyName);
            }
        }

    }

Полный голый проект https://wetransfer.com/downloads/199f3db5d183e64cf9f20db4225d4c9820180702001102/f4f61b

sample

Как вы можете видеть в привязке проекта, прямой текст свойства отсутствует.

Я хочу, чтобы все это содержалось в usercontrol, поэтому я либо устанавливаю значение свойства usercontrol в xaml, либо привязываюсь к нему, без добавления в основное окно xaml или код.

1 Ответ

0 голосов
/ 02 июля 2018

Вы не привязываете свойство Text TextBlock к свойству TxT UserControl.

Установить относительный источник привязки

<TextBlock Text="{Binding TxT,
                  RelativeSource={RelativeSource AncestorType=UserControl}, ...}" .../>

или назначьте x:Name для UserControl и используйте привязку ElementName.


Затем вместо установки DataContext UserControl с помощью

<local:UserControlSample DataContext="{Binding UCData}" .../>

связать его свойство TxT:

<local:UserControlSample TxT="{Binding UCData.TxT}" .../>

РЕДАКТИРОВАТЬ: для того, чтобы связать непосредственно со свойствами объекта в его DataContext, как предполагалось с

<local:UserControlSample DataContext="{Binding UCData}" .../>

вам вообще не нужно объявлять какие-либо свойства в UserControl. Удалите объявление свойства зависимости TxT и напрямую свяжите элементы в XAML UserControl, как вы уже сделали:

<TextBlock Text="{Binding TxT, ...}"/>

Обратите внимание, что это не то, как обычно работает UserControl. Ваша теперь зависит от конкретного типа модели представления и не может быть повторно использована с другими моделями представления.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...