引用在附加属性的静态方法中创建的对象

时间:2014-02-09 01:39:14

标签: c# wpf

我正在学习WPF,并尝试创建一个完全可换肤的可配置步步高板。 该板包含许多引脚,这些引脚源自网格并包含许多椭圆(棋子)。引脚放置在另一个网格'MainGrid'上,该网格基本上是电路板。 用于创建引脚的参数作为字符串存储在资源目录中。该字符串实际上是电路板的附加属性。 (配置示例仅显示两个条形针的配置)

<Style x:Key="MainGrid_style" TargetType="Grid">
    // ...
    <Setter Property="bgb:BgBoard.BarParams" Value="Bottom,5,8,1,1,4/Top,5,8,6,1,4"/>
</Style>

样式应用于主网格,如下所示:

<Grid x:Name="MainGrid" Style="{DynamicResource MainGrid_style}">

我的电路板编码如下:

public partial class BgBoard : Window
{
    public static DependencyProperty BarParamsProperty = DependencyProperty.RegisterAttached("BarParams", typeof(string),
          typeof(BgBoard), new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.None,
          new PropertyChangedCallback(BarParamsPropertyChanged)));
    public static string GetBarParams(Grid Grid) { return Convert.ToString(Grid.GetValue(BarParamsProperty)); }
    public static void SetBarParams(Grid Grid, string Value) { Grid.SetValue(BarParamsProperty, Value); }
    private static void BarParamsPropertyChanged(Object Sender, DependencyPropertyChangedEventArgs e)
    {
        Grid Grid = (Grid)Sender;
        string[] sBarParams = GetBarParams(Grid).Split('/');
        for (int player = 0; player <= 1; player++)
        {
            // *** sBarParams[player] is further parsed and parameters are determined
            BgPin pin = new BgPin(type, size);
            // *** Set the other pin params
            pin.Name = "Bar" + player;
            Grid.Children.Add(pin);
        }
    }

这完美地工作,并按预期将两个条形针脚放在电路板上。 但是,现在我希望能够将两个引脚作为数组引用(_Bar [0]和_Bar [1])

所以我在主板上添加了以下字段:

    private BgPin[] _Bar = new BgPin[2];  

我无法通过附加属性实例化或分配这些引脚,因为BarParamsPropertyChanged方法是静态的。

所以在我的Board的构造函数中,我添加了:

public BgBoard()
{
    InitializeComponent();
    _Bar[0] = (BgPin)MainGrid.FindName("Bar0");
}

但是,这不起作用,因为_Bar [0]在此指令后仍为空。我有什么想法可以引用名为“Bar0”的对象作为_Bar [0]?任何解决方案都可以。它不需要通过'name'-property工作。

3 个答案:

答案 0 :(得分:0)

你可以这样试试:

  1. 创建静态事件
  2. 在构造函数
  3. 中为该事件订阅非静态方法
  4. 将逻辑添加到订阅者方法中的数组{},这将保证仅在BgPin创建后调用的逻辑
  5. 在静态方法(本例中为BgPin)中,调用静态事件以便调用subscriber方法
  6. 使类(在这种情况下为BarParamsPropertyChanged)实现BgBoard,并在IDisposable方法实现中取消订阅静态事件中的非静态方法。需要执行此步骤以确保类的实例可以正确地进行GC编辑。
  7. 例如(未经测试):

    Dispose

    [Reference]

答案 1 :(得分:0)

在代码隐藏中创建GUI元素并不是WPF的设计方式。您应该创建数据模型来表示您的电路板,然后使用数据绑定在视图中显示该数据。要查看一个很好的示例,请查看my answer to another SO question about displaying a chess board

答案 2 :(得分:0)

自己找到解决方案。我在静态方法中添加了以下代码:

BgBoard Board = (BgBoard)Grid.Parent;
Board._Bar[player] = pin;  

这是完整的编码: 皮肤文件的XAML:

<Style x:Key="MainGrid_style" TargetType="Grid">
    <Setter Property="Background">
        <Setter.Value>
            <ImageBrush ImageSource="pack://SiteOfOrigin:,,,/Graphics/WoodBoard.jpg"/> 
        </Setter.Value>
    </Setter>
    <Setter Property="bgb:BgBoard.GridRows" Value="44*,45*,45*,20*,44*,48*,44*,20*,45*,45*,44*"/>
    <Setter Property="bgb:BgBoard.GridColumns" Value="36*,30*,30*,30*,30*,30*,30*,2*,30*,1*,30*,30*,30*
                                                     ,30*,30*,30*,13*,33*,36*,22*,37*,4*,37*,20*,30*"/>
    <Setter Property="bgb:BgBoard.BarParams" Value="Bottom,5,8,1,1,4/Top,5,8,6,1,4"/>
</Style>

XAML BgBoard

<Grid x:Name="MainGrid" Style="{DynamicResource MainGrid_style}">

Codebehind BgBoard

public partial class BgBoard : Window 
{

    public static DependencyProperty BarParamsProperty = DependencyProperty.RegisterAttached("BarParams", typeof(string),
          typeof(BgBoard), new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.None,
          new PropertyChangedCallback(BarParamsPropertyChanged)));
    public static string GetBarParams(Grid Grid) { return Convert.ToString(Grid.GetValue(BarParamsProperty)); }
    public static void SetBarParams(Grid Grid, string Value) { Grid.SetValue(BarParamsProperty, Value); }
    private static void BarParamsPropertyChanged(Object Sender, DependencyPropertyChangedEventArgs e)
{
        Grid Grid = (Grid)Sender;
        string[] sBarParams = GetBarParams(Grid).Split('/');
        for (int player = (int)Player.Player1; player <= (int)Player.Player2; player++)
        {
            string[] sBarParam = sBarParams[player].Split(',');
            string type = sBarParam[0];
            int size = Convert.ToInt32(sBarParam[1]);
            int column = Convert.ToInt32(sBarParam[2]);
            int row = Convert.ToInt32(sBarParam[3]);
            int columnspan = Convert.ToInt32(sBarParam[4]);
            int rowspan = Convert.ToInt32(sBarParam[5]);
            BgPin pin = new BgPin(type, size);
            Grid.SetColumn(pin, column);
            Grid.SetRow(pin, row);
            Grid.SetColumnSpan(pin, columnspan);
            Grid.SetRowSpan(pin, rowspan);
            pin.Player = (Player)player;
            Grid.Children.Add(pin);
            BgBoard Board = (BgBoard)Grid.Parent;
            Board._Bar[player] = pin;
        }
    }

    private BgPin[] _Bar = new BgPin[2];       

    public BgBoard()
    {
        InitializeComponent();
        _Bar[0].Checkers = 3;
    }

这样就可以让玩家1的3个棋子出现在栏上,就像我想要的那样。