2

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

块控件应作为独立的和作为不同用户控件的 DataTemplate 使用。

如果我在 Block 的 View 中设置 DataContext,独立版本效果很好,但不是 Sector View 的一部分。

如果我没有在 Block 的视图中设置 DataContext,它可以在 Sector 中工作,但不是独立的。

我的问题是,这是将 DataContext 留在 Block 的 View 中并将其设置在我使用 Control 或 ViewModel 的 View 中的唯一方法吗?

这是我的代码:

模块型号:

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
}

块的视图模型:

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()
    {
    }
}

扇区视图模型:

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:我希望我的英语没有我想象的那么差

4

2 回答 2

1

这是 WPF 新用户的常见问题。您有两种可能的解决方案。使用 MVVM 时,您不需要DataContext在任何地方设置 of UserControl。相反,您可以简单地添加一个DataTemplateApp.xaml进行配对:

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

这样,每当您显示 的实例时BlockViewModel,框架都会显示相关的BlockView(就像您在SectorView课堂上所做的那样)。

另一种选择是将 MVVM 用于UserControl(使用Bindable DependencyPropertys 代替),不在内部设置它,而是在内部元素上DataContext使用s :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

于 2013-11-11T09:37:01.323 回答
0

听起来像 Block 作为一个控件,它似乎参与了其他用户控件或模板的一部分,在我看来,mvvm 在这里不起作用,你应该使用 Dependency 属性。原谅我糟糕的英语。

于 2013-11-11T09:12:14.810 回答