wpf 如何在 ItemsControl 中绑定 DataTemplate

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25560594/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 12:26:02  来源:igfitidea点击:

How to bind the DataTemplate within an ItemsControl

c#wpfxamlbindingitemscontrol

提问by Alan Wayne

I do not understand the DataTemplate within the ItemTemplate. I have an ObservableCollection"StringViewModel" Transcription that provides the ItemsSource for an ItemsControl. Populating the Transcription collection with StringViewModel correctly displays these strings.

我不明白 ItemTemplate 中的 DataTemplate。我有一个 ObservableCollection"StringViewModel" Transcription,它为 ItemsControl 提供了 ItemsSource。使用 StringViewModel 填充 Transcription 集合会正确显示这些字符串。

At the time of displaying each string, I would like the XAML binding to call MyConverter such that additional code can be run on each item being displayed. (I am not trying to change what is displayed, but only perform some actions based on the position of what is displayed).

在显示每个字符串时,我希望 XAML 绑定调用 MyConverter,以便可以在显示的每个项目上运行附加代码。(我不是要更改显示的内容,而是仅根据显示内容的位置执行一些操作)。

In the following code, MyConverter is never called.

在以下代码中,从不调用 MyConverter。

What is the best way to call MyConverter on each item presented in the ItemsControl?

在 ItemsControl 中显示的每个项目上调用 MyConverter 的最佳方法是什么?

Any help is appreciated.

任何帮助表示赞赏。

C#

C#

public class StringViewModel : FrameworkElement {...}

private ObservableCollection<StringViewModel> transcription = new ObservableCollection<StringViewModel>();
    public ObservableCollection<StringViewModel> Transcription
    {
        get
        {
            return transcription;
        }
        set
        {
            transcription = value;
        }
    }

XAML

XAML

<ItemsControl 
                ItemsSource="{Binding Transcription}"
                >
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <Canvas 
                            Background="Transparent"
                             Width="{x:Static h:Constants.widthCanvas}" 
                             Height="{x:Static h:Constants.heightCanvas}" 
                             />
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel> 
                <ItemsControl.ItemTemplate>
                    <DataTemplate>              <!-- THIS DOES NOT WORK -->

                        <ContentControl Content="{Binding Converter={StaticResource MyConverter}}"/>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>

My attempt to change this to:

我尝试将其更改为:

<ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <StringViewModel ft="{Binding Path=., Converter={StaticResource MyConverter}}"/>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>

Results in:

结果是:

ItemTemplate and ItemTemplateSelector are ignored for items already of the ItemsControl's container type; Type='StringViewModel'

ItemTemplate 和 ItemTemplateSelector 对于已经属于 ItemsControl 的容器类型的项目将被忽略;类型='字符串视图模型'

What to do?

该怎么办?

The StringViewModel is defined as:

StringViewModel 定义为:

  public class StringViewModel : FrameworkElement, INotifyPropertyChanged
{

    public StringViewModel()
    {
    }

    public StringViewModel(
        Point topleft, 
        string text, 
        double fontsizediu,                         
        SolidColorBrush brush, 
        Func<FormattedText,FormattedText> f,        
        double lineheight)
    {
        this.text = text;
        this.emSize = fontsizediu;                 
        this.color = brush;
        this.topleft = topleft;
        this.lineheight = lineheight;              
        this.f = f;
    }

    protected override void OnRender(DrawingContext dc)
    {

        ft = new FormattedText(
            text, 
            CultureInfo.CurrentCulture, 
            FlowDirection.LeftToRight,
            new Typeface(new FontFamily("Segoe Script"), FontStyles.Italic, FontWeights.Normal, FontStretches.Normal),
            emSize, 
            color);


        ft.TextAlignment = TextAlignment.Left;

        // apply special styles
        ft = f(ft);
        dc.DrawText(ft, topleft);

    }

    private string text;
    private double emSize;
    private SolidColorBrush color;
    private Func<FormattedText, FormattedText> f;

    public Point topleft;
    private double? Lineheight;


    private FormattedText _ft;
    public FormattedText ft
    {
        get
        {
            return _ft;
        }
        set
        {
            if (_ft != value)
            {
                _ft = value;
                OnPropertyChanged("ft");
            }
        }
    }

采纳答案by Rang

Update:

更新:

I advice you not realize Render in ViewModel,Actually your StringViewModel should be a StringModel like this : (just contains some properties)

我建议你不要在 ViewModel 中实现 Render,实际上你的 StringViewModel 应该是这样的 StringModel :(只包含一些属性)

public class StringModel :  INotifyPropertyChanged
{

    public StringModel()
    {
    }

    public StringModel(
        Point topleft,
        string text,
        double fontsizediu,
        SolidColorBrush brush,
        double lineheight)
    {
        this.text = text;
        this.emSize = fontsizediu;
        this.color = brush;
        this.topleft = topleft;
        this.lineheight = lineheight;
    }


    public string text;
    public double emSize;
    public SolidColorBrush color;

    public Point topleft;
    public double? lineheight;


    private FormattedText _ft;
    public FormattedText ft
    {
        get
        {
            return _ft;
        }
        set
        {
            if (_ft != value)
            {
                _ft = value;
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

and then ,realize render in converter:

然后,在转换器中实现渲染:

 public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        var stringviewmodel = value as StringModel;
        if (stringviewmodel != null)
        {
            stringviewmodel.ft = new FormattedText(
           stringviewmodel.text,
           CultureInfo.CurrentCulture,
           FlowDirection.LeftToRight,
           new Typeface(new FontFamily("Segoe Script"), FontStyles.Italic, FontWeights.Normal, FontStretches.Normal),
           stringviewmodel.emSize,
           stringviewmodel.color);


            stringviewmodel.ft.TextAlignment = TextAlignment.Left;

            // apply special styles

            Image myImage = new Image();

            DrawingVisual drawingVisual = new DrawingVisual();
            DrawingContext dc = drawingVisual.RenderOpen();
            dc.DrawText(stringviewmodel.ft, stringviewmodel.topleft);
            dc.Close();

            RenderTargetBitmap bmp = new RenderTargetBitmap(180, 180, 120, 96, PixelFormats.Pbgra32);
            bmp.Render(drawingVisual);
            myImage.Source = bmp;

            return myImage;
        }
        else
        {
            return null;
        }
    }

here is itemcontrol's code:

这是 itemcontrol 的代码:

 <ItemsControl x:Name="ic" ItemsSource="{Binding LST}" Margin="0,0,143,185">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel 
                        Background="Transparent"
                         />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <ContentControl Content="{Binding Converter={StaticResource myconverter}}"/>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>

and Main code is:

和主要代码是:

 public partial class MainWindow : Window
{
    private List<StringModel> lst;

    public List<StringModel> LST
    {
        get { return lst; }
        set { lst = value; }
    }

    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = this;
        LST = new List<StringModel>();

        StringModel vm = new StringModel(new Point(20, 20), "123", 14, Brushes.Red, 2);
        LST.Add(vm);

        vm = new StringModel(new Point(20, 20), "456", 16, Brushes.Blue, 3);
        LST.Add(vm);

        vm = new StringModel(new Point(20, 20), "789", 18, Brushes.Green, 4);
        LST.Add(vm);



    }
}

finally, the effect of it:

最后,它的效果:

enter image description here

在此处输入图片说明