Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在转换器中初始化StackPanel并使用ContentPresenter呈现它是一种好的MVVM实践吗?_C#_Wpf_Mvvm_Ivalueconverter - Fatal编程技术网

C# 在转换器中初始化StackPanel并使用ContentPresenter呈现它是一种好的MVVM实践吗?

C# 在转换器中初始化StackPanel并使用ContentPresenter呈现它是一种好的MVVM实践吗?,c#,wpf,mvvm,ivalueconverter,C#,Wpf,Mvvm,Ivalueconverter,这是我上次提问的后续问题 最后一次回答者有这样的评论: 确切地说,另外,您不应该在代码中操作UI元素,而应该熟悉MVVM 回答者还使用了椭圆曲线测量法和路径很好地回答了问题。但是,由于我对路径不太熟悉,我正试图找到另一种更“适合”我的风格的方法 我找到了另一种方法: 转换器类 public class NoteOctaveConverter : IValueConverter { private const double _dotDiameter = 3; private rea

这是我上次提问的后续问题

最后一次回答者有这样的评论:

确切地说,另外,您不应该在代码中操作UI元素,而应该熟悉MVVM

回答者还使用了
椭圆曲线测量法
路径
很好地回答了问题。但是,由于我对
路径不太熟悉,我正试图找到另一种更“适合”我的风格的方法

我找到了另一种方法:

转换器类

public class NoteOctaveConverter : IValueConverter
{
    private const double _dotDiameter = 3;
    private readonly Thickness _dotMargin = new Thickness(0.25);
    private SolidColorBrush _dotFill;
    private readonly HorizontalAlignment _dotHzAlign = HorizontalAlignment.Center;

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        int octave = (int)value;
        List<Ellipse> dots = new List<Ellipse>();
        StackPanel stack = new StackPanel();

        if ((octave > 0 && parameter as string == "TOP") || (octave < 0 && parameter as string == "BOT"))
        {
            _dotFill = Brushes.Black;
        }
        else
        {
            _dotFill = Brushes.Transparent;
        }

        for (int i = 0; i < Math.Abs(octave); i++)
        {
            dots.Add(new Ellipse());
            dots[i].Width = _dotDiameter;
            dots[i].Height = _dotDiameter;
            dots[i].Margin = _dotMargin;
            dots[i].Fill = _dotFill;
            dots[i].HorizontalAlignment = _dotHzAlign;

            stack.Children.Add(dots[i]);
        }

        return stack;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}
public class NoteOctaveConverter : IValueConverter
{
    private const double _dotDiameter = 3;
    private readonly Thickness _dotMargin = new Thickness(0.25);
    private SolidColorBrush _dotFill;

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        int octave = (int)value;
        List<DotMockup> dots = new List<DotMockup>();

        if ((octave > 0 && parameter as string == "TOP") || (octave < 0 && parameter as string == "BOT"))
        {
            _dotFill = Brushes.Black;
        }
        else
        {
            _dotFill = Brushes.Transparent;
        }

        for (int i = 0; i < Math.Abs(octave); i++)
        {
            dots.Add(new DotMockup());
            dots[i].Diameter = _dotDiameter;
            dots[i].Margin = _dotMargin;
            dots[i].Fill = _dotFill;
        }

        return dots;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException();
    }
公共类NoteOctaveConverter:IValueConverter
{
私有常数双点直径=3;
私有只读厚度_dotMargin=新厚度(0.25);
私有SolidColorBrush_dotFill;
私有只读水平对齐_dotHzAlign=水平对齐.Center;
公共对象转换(对象值、类型targetType、对象参数、CultureInfo区域性)
{
int倍频程=(int)值;
列表点=新列表();
StackPanel stack=新的StackPanel();
if((倍频程>0&¶meter as string==“TOP”)| |(倍频程<0&¶meter as string==“BOT”))
{
_点填充=画笔。黑色;
}
其他的
{
_点填充=画笔。透明;
}
for(int i=0;i
我就是这样向视图展示它的:

 <ContentPresenter Grid.Column="1" Grid.Row="2"
                      Content="{Binding Path=MusicalNotation.Octave, Converter={StaticResource NoteOctaveConverter}, ConverterParameter=BOT, Mode=OneWay}"
                      HorizontalAlignment="Center" VerticalAlignment="Top"/>

Idk如果这就是回答者所说的“不操纵代码中的UI元素”(我是MVVM新手)的意思,但是,从MVVM的角度来看,这种方式*可以接受吗

*)此方式=使用
ContentPresenter
转换器
显示
堆栈面板

附加说明:

 <ContentPresenter Grid.Column="1" Grid.Row="2"
                      Content="{Binding Path=MusicalNotation.Octave, Converter={StaticResource NoteOctaveConverter}, ConverterParameter=BOT, Mode=OneWay}"
                      HorizontalAlignment="Center" VerticalAlignment="Top"/>
我之所以使用
ContentPresenter
方式而不是
路径
是因为我需要很好地理解我的工作,因为我可能必须在演讲环节中向我的讲师展示我的工作(我不想展示一些新的(有风险的),如果我有另一种更适合我的方法)

如果以我的方式使用
StackPanel
是一种不好的做法,请告诉我原因是什么


谢谢。

我建议您在内容演示者内容上使用DataTemplate

<ContentPresenter Content="{Binding X}"/>
  <COntentPresenter.ContentTemplate>
    <DataTemplate >
       <StackPanel>...</StackPanel>
    </DataTemplate>
  </COntentPresenter.ContentTemplate>
</ContentPresenter/>

...
显然,您需要在StackPanel中进行一些动态收集处理—要完成它,您可以阅读。这样的问题已经得到了回答

关于“从dataConverter返回控件是否是一种良好做法”:


我怀疑。因为转换器不是为返回完整的控件而设计的-这是datatemplates的任务。很明显,它们可以,但通常用于更简单的任务-一些附加格式,或颜色值。当他们创建控件时,他们违反了MVVM和“XAML中的UI最大化”原则。在这种情况下,他们这样做是没有好处的。更糟糕的是,除了公认答案中的好的基本答案之外,还有一种难以理解的转换方法取代了清晰的XAML和viewmodel逻辑。

以防有人想知道真正的答案

我的新DotMockup类(这是一个椭圆定义类,用于“模拟”真实椭圆)

我更新的转换器类

public class NoteOctaveConverter : IValueConverter
{
    private const double _dotDiameter = 3;
    private readonly Thickness _dotMargin = new Thickness(0.25);
    private SolidColorBrush _dotFill;
    private readonly HorizontalAlignment _dotHzAlign = HorizontalAlignment.Center;

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        int octave = (int)value;
        List<Ellipse> dots = new List<Ellipse>();
        StackPanel stack = new StackPanel();

        if ((octave > 0 && parameter as string == "TOP") || (octave < 0 && parameter as string == "BOT"))
        {
            _dotFill = Brushes.Black;
        }
        else
        {
            _dotFill = Brushes.Transparent;
        }

        for (int i = 0; i < Math.Abs(octave); i++)
        {
            dots.Add(new Ellipse());
            dots[i].Width = _dotDiameter;
            dots[i].Height = _dotDiameter;
            dots[i].Margin = _dotMargin;
            dots[i].Fill = _dotFill;
            dots[i].HorizontalAlignment = _dotHzAlign;

            stack.Children.Add(dots[i]);
        }

        return stack;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}
public class NoteOctaveConverter : IValueConverter
{
    private const double _dotDiameter = 3;
    private readonly Thickness _dotMargin = new Thickness(0.25);
    private SolidColorBrush _dotFill;

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        int octave = (int)value;
        List<DotMockup> dots = new List<DotMockup>();

        if ((octave > 0 && parameter as string == "TOP") || (octave < 0 && parameter as string == "BOT"))
        {
            _dotFill = Brushes.Black;
        }
        else
        {
            _dotFill = Brushes.Transparent;
        }

        for (int i = 0; i < Math.Abs(octave); i++)
        {
            dots.Add(new DotMockup());
            dots[i].Diameter = _dotDiameter;
            dots[i].Margin = _dotMargin;
            dots[i].Fill = _dotFill;
        }

        return dots;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException();
    }
公共类NoteOctaveConverter:IValueConverter
{
私有常数双点直径=3;
私有只读厚度_dotMargin=新厚度(0.25);
私有SolidColorBrush_dotFill;
公共对象转换(对象值、类型targetType、对象参数、CultureInfo区域性)
{
int倍频程=(int)值;
列表点=新列表();
if((倍频程>0&¶meter as string==“TOP”)| |(倍频程<0&¶meter as string==“BOT”))
{
_点填充=画笔。黑色;
}
其他的
{
_点填充=画笔。透明;
}
for(int i=0;i
最后,我更新了XAML部件以在StackPanel中显示数据

<ItemsControl Grid.Column="1" Grid.Row="2" 
                  ItemsSource="{Binding Path=MusicalNotation.Octave, Converter={StaticResource NoteOctaveConverter}, ConverterParameter=BOT, Mode=OneWay}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel IsItemsHost="True"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Ellipse HorizontalAlignment="Center" VerticalAlignment="Top"
                         Margin="{Binding Margin}" Fill="{Binding Fill}" 
                         Width="{Binding Diameter}" Height="{Binding Diameter}"/>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>


希望这会有所帮助。(虽然被接受的答案不会改变,因为你需要先从根本上理解它)

解决方案之后

很好,但我有几点建议:

1) 你的转换器还是太复杂了,我不喜欢。理想情况下,你的视图模型应该包含像这样的点模型

public IEnumerable<DotMockups> OctaveData { get {...}}
您应该将点模型的创建转移到viewmodel层,并将倍频程的计算转移到模型层

但是,实际上,如果不想使viewmodel过于复杂,可以保持原样

2) DotMockups成员太像UI了。如果您保持解决方案的原样,那么
if ((octave > 0 && parameter as string == "TOP") || (octave < 0 && parameter as string == "BOT"))
        {
            _dotFill = Brushes.Black;
        }
        else
        {
            _dotFill = Brushes.Transparent;
        }