开发者

WPF "partial forms"

开发者 https://www.devze.com 2023-02-12 05:22 出处:网络
I\'m making an application for DB migrations. I made a multithreaded framework with WPF GUI. I put someting like this in my namespace/folder:

I'm making an application for DB migrations. I made a multithreaded framework with WPF GUI. I put someting like this in my namespace/folder:

class Something : Migrator {
    public override Run(){
        //I would need this
        string valueOfMyCustomFieldOnForm = xyz.Text; //example

        int count = 500;
        for(int i = 0; i < 500; i++){
            //do something here
            OnProgressChanged(...); //call event, GUI is updated
        }
        OnCompleted(...); //migration completed
    }
}

Then using reflection I put all classes in that namespace onto dropdown list. When I choose one in a list and click Start, the Thread with code in Run method is started.

DB Host: TEXTBOX
DB Username: TEXTBOX
开发者_StackOverflowDB Password: TEXTBOX
--
Migrator custom field 1: TEXTBOX
Migrator custom field 2: TEXTBOX
...
--
List with migrated items - irrelevant

There are few commong field on GUI (like database host, username etc...). But for some of those migrators I would need custom fields on GUI (for example 3 extra textbox fields). What is the best way to do this in WPF? I need part of the GUI to be dynamic.


There's a lot of seemingly-irrelevant information in your question, which - I think - is really about mechanisms for creating metadata-driven UIs in WPF. Here's a way to approach that problem:

Suppose that you want to build a property-sheet-like UI: a grid that displays a row for each property, with a prompt and an input control of some kind. To do this, you're going to need a collection of objects, with each item in the collection including properties that describe the property and its value. A simple design would be a class that exposes a Prompt property and a Value property and that implements change notification.

Once you have created and populated this collection, you can implement an ItemsControl that displays it in a grid:

<ItemsControl ItemsSource="{Binding Properties}" Grid.IsSharedSizeScope="True">
   <ItemsControl.ItemTemplate>
      <DataTemplate DataType="PropertyViewModel">
         <Grid>
            <Grid.ColumnDefinitions>
               <ColumnDefinition SharedSizeGroup="Prompt"/>
               <ColumnDefinition SharedSizeGroup="Value"/>                   
            </Grid.ColumnDefinition>
            <Grid.RowDefinitions>
               <RowDefinition/>
            </Grid.RowDefinitions>
         </Grid>
         <Label Content="{Binding Prompt}"/>
         <TextBox Grid.Column="1" Text="{Binding Value, Mode=TwoWay}"/>
      </DataTemplate>
   </ItemsControl.ItemTemplate>
</ItemsControl>

This is pretty simple - the most complicated thing about it is using Grid.IsSharedSizeScope so that all of the grids that this control creates use the same column widths. You could also use a ListView instead of an ItemsControl, though using a ListView for this introduces a bunch of issues surrounding focus and selection that you may not want to deal with.

Note that because of the magic that is WPF template matching, you could conceivably implement the Value property as an object, and create different templates to handle the different possible types of the Value property - just like a real property sheet does. To do this, you'd create a template for each type, e.g.:

<DataTemplate DataType="{x:Type System:String}">
   <TextBox Text="{Binding Value, Mode=TwoWay}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type System:DateTime}">
   <DatePicker Value="{Binding Value, Mode=TwoWay}"/>
</DataTemplate>

etc. Then you'd change the template for the PropertyViewModel so that instead of showing the Value in a TextBox, it uses a ContentPresenter, e.g.:

<ContentPresenter Grid.Column="1" Content="{Binding}"/>
0

精彩评论

暂无评论...
验证码 换一张
取 消