私は現在、ユーザーがカスタム xaml 要素を GUI に追加し、特定のプロパティを設定できる uwp を構築しています。設定できるページの一般的なプロパティもあります。これを行うには、デザインページにプロパティ パネルがあります。このプロパティ パネルでは、選択した xaml 要素から変更可能なプロパティを表示するか、(ユーザーが特定の要素を 1 つ選択した場合) 一般的なプロパティを表示する必要があります。値がプロパティ パネルに動的に表示されるように、またプロパティ パネルで行われた変更がソースに渡されるように、双方向のデータ バインディングを使用したいと考えています。
選択した xaml 要素の詳細を表示するためにこの双方向バインディングを実装しても問題はありませんでしたが、一般的なプロパティの場合、バインディングは一方向にしか行かないように見えます。一般的なプロパティがコードで変更されると、ターゲット オブジェクトに渡されますが、GUI でデータが変更されると、データはソースに渡されません。
そこで、Web を検索し、依存関係プロパティの追加、private<-->public の変更、さまざまな方法での INotifyPropertyChanged の実装などによってコードを変更しようとしましたが、残念ながらどれも機能していないようです。
以下に、機能する C# コードと機能しない C# コード/xaml の両方を示します。誰かが問題を見つけることができれば、私は最も感謝しています。
デザイン ページのターゲット コントロールの一般的な xaml
<StackPanel x:Name="PropsPanel" Grid.Column="1" Grid.Row="1" Grid.RowSpan="2" Orientation="Vertical" Background="GhostWhite" BorderThickness="1" BorderBrush="GhostWhite" Margin="4">
<TextBlock Text="Properties" Margin="4,4,0,40" Foreground="Black" FontWeight="Bold"/>
<ContentControl Name="PropertiesPanel" Foreground="Black">
</ContentControl>
</StackPanel>
プロパティの双方向バインディングが機能する Datatemplate xaml
<DataTemplate x:Key="TimerElementTemplate">
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Margin="2" Text="Timer" FontWeight="SemiBold"/>
<TextBlock Grid.Row="1" Grid.Column="0" Margin="2" Text="Column "/>
<TextBlock Grid.Row="1" Grid.Column="1" Margin="2" Text="{Binding Path=ShowColumn, Mode=OneWay}" />
<TextBlock Grid.Row="2" Grid.Column="0" Margin="2" Text="Row " />
<TextBlock Grid.Row="2" Grid.Column="1" Margin="2" Text="{Binding Path=ShowRow, Mode=OneWay}"/>
<TextBlock Grid.Row="3" Grid.Column="0" Margin="2" Text="Name "/>
<TextBox Grid.Row="3" Grid.Column="1" BorderThickness="1" Margin="2" Text="{Binding Path=ElementName, Mode=TwoWay}" />
<TextBlock Grid.Row="4" Grid.Column="0" Margin="2" Text="Label " />
<TextBox Grid.Row="4" Grid.Column="1" Margin="2" BorderThickness="1" Text="{Binding Path=Label, Mode=TwoWay}" />
</Grid>
</DataTemplate>
データコンテキストを設定するための作業コード
private void GOnPointerReleased(object sender, PointerRoutedEventArgs pointerRoutedEventArgs)
{
if (_selectedGuiElement != null)
{
_selectedGuiElement.BorderThickness = new Thickness(0);
}
PropertiesPanel.DataContext = sender;
PropertiesPanel.ContentTemplate = Resources[sender.GetType().Name + "Template"] as DataTemplate;
var element = sender as GuiElement;
element.BorderBrush = new SolidColorBrush(Colors.Crimson);
element.BorderThickness = new Thickness(2.0);
_selectedGuiElement = element;
}
表示可能なプロパティを持つ要素は、Grid Xaml コントロールから継承する GUI 要素です。表示するプロパティは、GUIElementProperty 属性でマークされています。GUI 要素のコードは次のとおりです。
public class GuiElement : Grid
{
protected string _elementType;
public GuiElement(bool design)
{
DesignState = design;
SetElementType();
AddContent();
if(DesignState)
AllowDrop = true;
}
//overridable method to set Type and Type related properties
public virtual void SetElementType()
{
_elementType = "";
GuiBackground = new SolidColorBrush(Colors.DarkGray);
}
//overridable method to set lay-out content for each type
public virtual void AddContent()
{
Background = GuiBackground;
BorderThickness = new Thickness(1);
BorderBrush = new SolidColorBrush(Colors.GhostWhite);
SetColumnSpan(this, ColumnSpan);
SetRowSpan(this, RowSpan);
}
// shortcuts for Grid.Column and Grid.Row properties and other general properties
[GuiElementProperty("lbl", "Column", 2)]
public int Column
{
get { return GetColumn(this); }
set { SetColumn(this, value); }
}
public string ShowColumn
{
get { return Column.ToString(); }
}
[GuiElementProperty("lbl", "Row", 1)]
public int Row
{
get { return GetRow(this); }
set { SetRow(this, value); }
}
public string ShowRow
{
get { return Row.ToString(); }
}
public int ColumnSpan { get; set; } = 1;
public int RowSpan { get; set; } = 1;
public bool DesignState { get; set; }
public SolidColorBrush GuiBackground { get; set; }
public int Id { get; set; }
[GuiElementProperty("lbl", "Type", 0)]
public string ElementType { get { return _elementType; } }
}
}
これまでの作業コード...今問題のある部分
機能不全の双方向バインディングで一般的なプロパティを表示するための Datatemplate xaml
<DataTemplate x:Key="StartElementTemplate">
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Margin="2" Text="Session" FontWeight="SemiBold"/>
<!--<Button Foreground="GhostWhite" Grid.Row="0" Grid.Column="1" Content="X" Click="ButtonDeleteFromProperties_OnClick"></Button>-->
<TextBlock Grid.Row="1" Grid.Column="0" Margin="2" Text="Name "/>
<TextBlock Grid.Row="1" Grid.Column="1" Margin="2" Text="{Binding Path=DesignName, Mode=OneWay}"/>
<TextBlock Grid.Row="2" Grid.Column="0" Margin="2" Text="Time Limit (true/false) "/>
<TextBox Grid.Row="2" Grid.Column="1" Margin="2" BorderThickness="1" Text="{Binding Path=LimitedTime, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<TextBlock Grid.Row="3" Grid.Column="0" Margin="2" Text="Max. duration (hh:mm:ss) "/>
<TextBox Grid.Row="3" Grid.Column="1" BorderThickness="1" Margin="2" Text="{Binding Path=Timelimit, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>
</DataTemplate>
一般的なプロパティを持つクラスのコード
public class SessionProps : INotifyPropertyChanged
{ private string _designname;
private bool _limitedtime;
private TimeSpan _timelimit;
[GuiElementProperty("txtbx", "Design name", 0)]
public string DesignName
{
get { return _designname; }
set
{
_designname = value;
NotifyPropertyChanged();
}
}
[GuiElementProperty("bool", "Time limit", 1)]
public bool LimitedTime
{
get { return _limitedtime; }
set
{
_limitedtime = value;
NotifyPropertyChanged();
}
}
[GuiElementProperty("txtbx", "Max. Duration (hh:mm:ss)", 2)]
public TimeSpan Timelimit
{
get { return _timelimit; }
set
{
_timelimit = value;
NotifyPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
一般プロパティ クラスのインスタンスの作成
public sealed partial class DesignPage : Page
{
private SessionProps _props = new SessionProps() {DesignName = "", LimitedTime = false, Timelimit = TimeSpan.Zero};
このソースへのコード バインディング コントロール
private void SOnPointerReleased(object sender, PointerRoutedEventArgs e)
{
if (_selectedGuiElement != null)
{
_selectedGuiElement.BorderThickness = new Thickness(0);
}
PropsPanel.DataContext = _props;
PropertiesPanel.ContentTemplate = Resources[sender.GetType().Name + "Template"] as DataTemplate;
var element = sender as GuiElement;
element.BorderBrush = new SolidColorBrush(Colors.Crimson);
element.BorderThickness = new Thickness(2.0);
_selectedGuiElement = element;
}
ここで見落としている小さなものがあることを願っていますが、どんな助けでも大歓迎です! 十分な情報を提供できたと思いますが、まだ不明な点があれば質問してください。