You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF中在ScrollViewer内绑定动态创建控件(Catel MVVM迁移)

Hey there! Let's walk through how to migrate your dynamic XML-to-control logic from .NET 4.0/VS2010 to .NET 4.6.2 with Catel MVVM, specifically getting those controls loaded into a ScrollViewer when the view initializes.

Step 1: Set Up Your Catel View & ViewModel Structure

First, make sure your view inherits from Catel's Window (to leverage built-in MVVM features) and create a matching ViewModel.

View XAML (YourView.xaml)

We'll place a ScrollViewer and bind its content to a property in the ViewModel:

<catel:Window x:Class="YourApp.YourView"
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              xmlns:catel="http://schemas.catelproject.com">
    <Grid>
        <!-- Bind ScrollViewer content to our dynamic control property -->
        <ScrollViewer Content="{Binding DynamicContent}" 
                      VerticalScrollBarVisibility="Auto"
                      HorizontalScrollBarVisibility="Auto"/>
    </Grid>
</catel:Window>

ViewModel (YourViewModel.cs)

Add a property to hold the dynamically generated root control, using Catel's built-in property change notification:

using Catel.MVVM;
using System.Windows;

public class YourViewModel : ViewModelBase
{
    private UIElement _dynamicContent;
    
    // This property will hold our generated controls
    public UIElement DynamicContent
    {
        get => _dynamicContent;
        set => SetProperty(ref _dynamicContent, value);
    }
}

Step 2: Migrate the XML-to-Control Generation Logic

You have two clean approaches here, depending on whether you want to keep view-related code in the view layer or use a service for reusability.

Option A: Generate Controls Directly in the View (Simple)

Since generating UI elements is view-specific, you can handle this in the view's code-behind when it loads:

using Catel.Windows;
using System.IO;
using System.Windows;
using System.Windows.Markup;

public partial class YourView : Catel.Windows.Window
{
    public YourView()
    {
        InitializeComponent();
        Loaded += OnViewLoaded;
    }

    private void OnViewLoaded(object sender, RoutedEventArgs e)
    {
        var viewModel = DataContext as YourViewModel;
        if (viewModel == null) return;

        // Replace with your XML file path or loading logic
        var xmlFilePath = "path/to/your/layout.xml";
        viewModel.DynamicContent = GenerateControlsFromXml(xmlFilePath);
    }

    private UIElement GenerateControlsFromXml(string filePath)
    {
        // Reuse your existing XML parsing logic here
        var xmlContent = File.ReadAllText(filePath);
        return XamlReader.Parse(xmlContent) as UIElement;
    }
}

Option B: Use a Service for Reusability (Clean MVVM)

If you want to reuse the XML generation logic across multiple views, create a service and inject it into the ViewModel:

  1. Create the Service Interface & Implementation
using System.Windows;

public interface IXmlControlGenerator
{
    UIElement GenerateFromFile(string xmlFilePath);
}

public class XmlControlGenerator : IXmlControlGenerator
{
    public UIElement GenerateFromFile(string xmlFilePath)
    {
        // Your existing XML-to-control logic here
        var xmlContent = File.ReadAllText(xmlFilePath);
        return XamlReader.Parse(xmlContent) as UIElement;
    }
}
  1. Register the Service in Catel's Container
    In your App.xaml.cs:
using Catel.IoC;
using System.Windows;

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        // Register the service with Catel's dependency injection
        var serviceLocator = ServiceLocator.Default;
        serviceLocator.RegisterType<IXmlControlGenerator, XmlControlGenerator>();

        base.OnStartup(e);
    }
}
  1. Call the Service from the ViewModel
    Update your ViewModel to generate controls when it initializes:
using Catel.MVVM;
using System.Threading.Tasks;

public class YourViewModel : ViewModelBase
{
    private readonly IXmlControlGenerator _controlGenerator;

    public UIElement DynamicContent { get; private set; }

    // Inject the service via constructor (Catel handles this)
    public YourViewModel(IXmlControlGenerator controlGenerator)
    {
        _controlGenerator = controlGenerator;
    }

    protected override async Task InitializeAsync()
    {
        await base.InitializeAsync();

        // Generate controls when the ViewModel initializes
        DynamicContent = _controlGenerator.GenerateFromFile("path/to/your/layout.xml");
        RaisePropertyChanged(nameof(DynamicContent));
    }
}

Key Notes to Avoid Pitfalls

  • Data Context for Dynamic Controls: If your generated controls need to bind to ViewModel properties, set their DataContext to the ViewModel when generating them (e.g., rootElement.DataContext = this; in the service or view).
  • XAML Validity: Ensure your XML is valid WPF XAML (use XamlReader.Parse safely with try/catch blocks to handle parsing errors).
  • Catel Property Notifications: Use SetProperty or RaisePropertyChanged to ensure the view updates when DynamicContent changes.

内容的提问来源于stack exchange,提问作者user2086641

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:48:59