繁体   English   中英

在DataContext稍有不同的情况下,如何重用UserControl?

[英]How to reuse a UserControl in situations where the DataContext is slightly different?

这是我在StackOverflow上的第一篇文章,也是我的第一个问题。 我已经在WPF中使用MVVM模式(称为“块”)创建了一个UserControl。 此UserControl应该在另一个UserControl中用作ListBox(称为Sector)的DataTemplate。

块控件应独立使用,也可以作为不同UserControl的DataTemplate使用。

如果在“块视图”中设置DataContext,则独立版本的效果很好,但不能作为“扇区视图”的一部分。

如果未在“块视图”中设置DataContext,则它可以在“扇区”中工作,但不能独立运行。

我的问题是,这是将DataContext保留在Block视图中并在使用控件或ViewModel的视图中进行设置的唯一方法吗?

这是我的代码:

块的型号:

public class BlockModel : ModelBase
{
    #region private Variables

    string blockName = "Block";
    string blockContent = "00000";

    #endregion private Variables

    #region Properties

    public string BlockName
    {
        get { return blockName; }
        set { blockName = value; NotifyPropertyChange("BlockName "); }
    }

    public string BlockContent
    {
        get { return blockContent; }
        set { blockContent = value; NotifyPropertyChange("BlockContent"); }
    }

    #endregion Properties

    #region ctor

    public BlockModel () { }

    #endregion ctor
}

块的ViewModel:

public class BlockViewModel : ViewModelBase
{
    #region private Variables

    string charToFill = "0";
    DelegateCommand fillWithChar;
    BlockModel dataModel = new BlockModel();

    #endregion private Variables

    #region Properties

    public Models. BlockModel DataModel
    {
        get { return dataModel; }
        set { dataModel = value; }
    }

    public string BlockContent
    {
        get { return dataModel. BlockContent; }
        set
        {
            if (dataModel. BlockContent != value)
            {
                dataModel. BlockContent = value;
                NotifyPropertyChange ("BlockContent");
            }
        }
    }

    public string BlockName
    {
        get { return dataModel. BlockName; }
        set
        {
            if (dataModel. BlockName != value)
            {
                dataModel. BlockName = value;
                NotifyPropertyChange("BlockName");
            }
        }
    }


    public string CharToFill
    {
        get { return charToFill; }
        set
        {
            if (charToFill != value)
            {
                charToFill = value;
                NotifyPropertyChange ("CharToFill");
            }
        }
    }


    public ICommand FillWithChar
    {
        get
        {
            if (fillWithChar == null)
                fillWithChar = new DelegateCommand(FillText);
            return fillWithChar;
        }
    }

    #endregion Properties

    #region ctor

    public BlockViewModel()
    {

    }

    #endregion ctor

    #region Methods

    private void FillText()
    {
        CodingBlockContent = CodingBlockContent.PadLeft(32, charToFill[0]);
    }

    #endregion Methods

}

区块视图:

<UserControl x:Class="…./Block"
         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:…/Controls"
         mc:Ignorable="d" d:DesignWidth="460" d:DesignHeight="44">
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="124" />
        <ColumnDefinition Width="301" />
        <ColumnDefinition Width="30"/>
        <ColumnDefinition/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="30"></RowDefinition>

    </Grid.RowDefinitions>
    <TextBlock Grid.Row="0" Grid.Column="0" Text="{Binding BlockName}" 
               HorizontalAlignment="Left" VerticalAlignment="Center" FontSize="14" Margin="2,6"/>
    <ComboBox FontFamily="Consolas" Grid.Row="00" Grid.Column="1" 
              Text="{Binding BlockContent, Mode=TwoWay}" 
              Tag="{Binding BlockName}" Name="cbxBlock" FontSize="14" 
              HorizontalAlignment="Left" VerticalAlignment="Center" Width="290" Margin="1,4,0,5" IsEditable="True" Height="26">
        <ComboBoxItem Content=""></ComboBoxItem>
        <ComboBoxItem Content="0000000000000"></ComboBoxItem>
        <StackPanel HorizontalAlignment="Left" VerticalAlignment="Top" Orientation="Horizontal">
            <TextBox Margin="10,2,0,2" Text="0" Width="24" FontSize="14" Name="tbxChar" MaxLength="1"></TextBox>
            <TextBlock Margin="10,2,0,2" Text="auffüllen" VerticalAlignment="Center" FontSize="14"></TextBlock>
            <Button Margin="10,2,0,2" Content="Ausführen" Width="100"  Command="{Binding FillWithChar}"></Button>
        </StackPanel>
    </ComboBox>
    <TextBlock Grid.Row="0" Width="30" Grid.Column="2" Text="{Binding CodingBlockContent.Length}" 
               HorizontalAlignment="Left" VerticalAlignment="Center" FontSize="14" Margin="2,6,0,6" Grid.ColumnSpan="2"/>
</Grid>

行业模式:

public class SectorModel
{
    #region private Variables

    int blockAmount = 4;
    string sectorNumber = "Sektor";
    int blockBegin = 0;
    bool isSectorInUse = false;

    #endregion private Variables

    #region Properties

    public string SectorNumber
    {
        get { return sectorNumber; }
        set { sectorNumber = value;}
    }

    public int BlockBegin
    {
        get { return blockBegin; }
        set
        {
            blockBegin = value;
        }
    }

    public bool IsSectorInUse
    {
        get { return isSectorInUse; }
        set { isSectorInUse = value;}
    }

    public int BlockAmount
    {
        get { return blockAmount; }
        set
        {
            blockAmount = value;;
        }
    }

    #endregion Properties

  public SectorModel()
    {
    }
}

部门的ViewModel:

public class SectorViewModel : ViewModelBase
{
    #region private Variables

    SectorModel dataModel = new SectorModel();
    ObservableCollection<BlockViewModel> sectorBlocks = new ObservableCollection<BlockViewModel>();

    #endregion private Variables

    #region Properties

    public SectorModel DataModel
    {
        get { return dataModel; }
        set { dataModel = value; }
    }

    public ObservableCollection<BlockViewModel> SectorBlocks
    {
        get { return sectorBlocks; }
        set { sectorBlocks = value; NotifyPropertyChange ("SectorBlocks"); }
    }

    public string SectorNumber
    {
        get { return "Sektor " + DataModel.SectorNumber; }
        set { DataModel.SectorNumber = value; NotifyPropertyChange ("SectorNumber"); }
    }

    public int BlockBegin
    {
        get { return DataModel.BlockBegin; }
        set
        {
            DataModel.BlockBegin = value;
            SetBlocks();
            OnPropertyChanged("BlockBegin");
        }
    }

    public bool IsSectorInUse
    {
        get { return DataModel.IsSectorInUse; }
        set { DataModel.IsSectorInUse = value; NotifyPropertyChange ("IsSectorInUse"); }
    }

    public int BlockAmount
    {
        get { return DataModel.BlockAmount; }
        set
        {
            DataModel.BlockAmount = value;
            SetBlocks();
            NotifyPropertyChange ("CodingBlockAmount");
        }
    }

    #endregion Properties

    void SetBlocks()
    {
        while (SectorBlocks.Count != BlockAmount)
        {
            SectorBlocks.Add(new BlockViewModel());
        }

        int begin = BlockBegin;

        foreach (BlockViewModel block in SectorBlocks)
        {
            block.CodingBlockName = "Block " + begin.ToString().PadLeft(2, '0');
            block++;
        }
    }

    public SectorViewModel() 
    {
        SetBlocks();
    }
}

部门观点:

<UserControl xmlns:Views="clr-namespace:…/RFIDControls"  x:Class="…/Sector"
        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="473">
<Border BorderBrush="Black" BorderThickness="0,0,0,1">
    <Expander Name="expMain" Margin="0,0,4,0">
        <Expander.Header>
            <Grid Name="grdHeader">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="100" />
                    <ColumnDefinition Width="300" />
                    <ColumnDefinition Width="30" />
                </Grid.ColumnDefinitions>
                <TextBlock Grid.Column="0" Grid.Row="0" Height="24" Text="{Binding SectorNumber}" HorizontalAlignment="Left" VerticalAlignment="Center" FontSize="14" FontWeight="Bold" Panel.ZIndex="98"/>
                <CheckBox Grid.Column="2" VerticalAlignment="Center" IsChecked="{Binding IsSectorInUse}"></CheckBox>
            </Grid>
        </Expander.Header>
        <Grid>
            <ListBox ItemsSource="{Binding SectorBlocks}" Name="listBox">
                <ListBox.ItemTemplate>
                    <DataTemplate DataType="{x:Type Views:BlockViewModel}">
                        <Views:Block/>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
        </Grid>
    </Expander>
</Border>

谢谢。

来自德国的问候

多米尼克

PS:我希望我的英语不会像我想象的那样糟糕

对于WPF的新用户来说,这是一个普遍的问题。 您有两种可能的解决方案。 使用MVVM时,无需在任何位置设置UserControlDataContext 相反,您可以简单地将DataTemplate添加到App.xaml中进行配对:

<DataTemplate DataType="{x:Type ViewModels:BlockViewModel}">
    <Views:BlockView />
</DataTemplate>

这样,无论何时显示BlockViewModel的实例,框架都会显示相关的BlockView (就像您在SectorView类中所做的SectorView )。

另一种选择是不对 UserControl使用MVVM(改为使用Bindable DependencyProperty ), 不在内部设置其DataContext而对内部元素使用RelativeSource Binding

<TextBlock Grid.Row="0" Grid.Column="0" Text="{Binding DataContext.BlockName, 
    RelativeSource={RelativeSource AncestorType={
    x:Type YourXmlNamespacePrefix:BlockView}}}" HorizontalAlignment="Left" 
    VerticalAlignment="Center" FontSize="14" Margin="2,6"/>

使用此方法, RelativeSource Binding将查看当前设置为DataContext任何对象。

听起来像Block充当控件,似乎参与了其他usercontrol或Template的一部分,我认为mvvm在这里不起作用,您应该改用Dependency属性。 原谅我可怜的英语。

暂无
暂无

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

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