开发者

Basic WPF Layout question

I am learning WPF and am trying to follow some sort of best practice. I am kind of lost at the moment, and need some direction.

I am creating a very simple app that reads a text file (error log) and splits it into the individual error messages. I want to display these messages (stored in a model object) as a list of messages. Since the list can consist of many items and I want the window to be resizeable, I need a a vertical scroll bar, but I want the content to wrap (i.e. no need for a horizontal scroll bar).

<Window x:Class="ErrorLog.UI.WPF.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.mic开发者_JAVA技巧rosoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="800" Width="1200" Loaded="Window_Loaded">

<StackPanel Name="mainContainer">
    <StackPanel Orientation="Horizontal" Name="Menu">
        <Button Name="Refresh">Refresh</Button>
    </StackPanel>        
    <ScrollViewer VerticalScrollBarVisibility="Auto">
        <StackPanel Name="errorMessagePlaceHolder"></StackPanel>
    </ScrollViewer>
</StackPanel>

I am at the moment reading the file in the code behind and adding to the stackPanel as a bunch of textboxes with the value being the error message. I have also added some mouseover effects like this:

private void LoadData()
    {
        IErrorLogReader errorLogReader = new ErrorLogReader();
        var errors = errorLogReader.RetrieveErrors();

        if (errors.Count == 0)
        {
            TextBox noErrors = new TextBox();
            noErrors.Text = "No errors found";
            errorMessagePlaceHolder.Children.Add(noErrors);
        }
        else
        {
            for (var i = errors.Count - 1; i > 0; i--)
            {
                TextBox errorMessage = new TextBox();

                errorMessage.IsReadOnly = true;
                errorMessage.Padding = new Thickness(10);

                errorMessage.Text = errors[i].ErrorMessage;
                errorMessage.TextWrapping = TextWrapping.Wrap;

                errorMessage.MouseEnter += ErrorMessageMouseEnter;
                errorMessage.MouseLeave += ErrorMessageMouseLeave;

                errorMessagePlaceHolder.Children.Add(errorMessage);
            }
        }
    }

    protected void ErrorMessageMouseEnter(object sender, RoutedEventArgs e)
    {
        ((TextBox) sender).Background = Brushes.AntiqueWhite;
    }

    protected void ErrorMessageMouseLeave(object sender, RoutedEventArgs e)
    {
        ((TextBox) sender).Background = null;
    }

So the first things I want to know is:

  • Is the way I am binding ok?
  • Scroll bar is coming up disabled
  • Is the way I am doing the mouseover effect bad?

Cheers.


Is the way I am binding ok?

It might work, but it's not best practice. Best practice is to use actual data binding. First, you need to replace your StackPanel with something that can be bound to a list. An ItemsControl is the thing closest to a simple StackPanel, other options would be, for example, a ListBox.

<ScrollViewer VerticalScrollBarVisibility="Auto">
    <ItemsControl Name="errorMessageList" />
</ScrollViewer>
private void LoadData()
{
    IErrorLogReader errorLogReader = new ErrorLogReader();
    var errors = errorLogReader.RetrieveErrors();

    errorMessageList.ItemsSource = errors;
}

To specify how you want the error messages to be displayed, you can set a template for the ItemsControl:

<ScrollViewer VerticalScrollBarVisibility="Auto">
    <ItemsControl Name="errorMessageList">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <TextBox IsReadOnly="true" ... Text="{Binding ErrorMessage}" />
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</ScrollViewer>

Scroll bar is coming up disabled

You are nesting your ScrollViewer inside a StackPanel... that won't work: The StackPanel takes as much vertical space as it needs, so the ScrollViewer will always have enough space and never show the scroll bar. You need to replace your top-level StackPanel by something that takes only as much space as is available; a DockPanel, for example:

<DockPanel Name="mainContainer">
    <StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Name="Menu">
        <Button Name="Refresh">Refresh</Button>
    </StackPanel>        
    <ScrollViewer VerticalScrollBarVisibility="Auto">
        <StackPanel Name="errorMessagePlaceHolder"></StackPanel>
    </ScrollViewer>
</StackPanel>

Is the way I am doing the mouseover effect bad?

That can be done with a style and a trigger instead. Define the following style:

<Window ...>
    <Window.Resources>
        <Style x:Key="hoverTextBox" TargetType="{x:Type TextBox}">
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="Background" Value="AntiqueWhite" />
                </Trigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    ...
</Window>

and assign it to your TextBox inside the DataTemplate:

<TextBox IsReadOnly="true" ... Text="{Binding ErrorMessage}"
         Style="{StaticResource hoverTextBox}" />
0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜