Как бы я внедрил в WPF самонастраивающийся фон для нескольких изображений ... похожий на Nine Patch на Android? - PullRequest
0 голосов
/ 03 августа 2011

Я новичок в WPF.

У меня есть приложение, которое разделено на две "панели", главную панель и панель сведений. Основная панель высокая, узкая и выровненная по левому краю. Панель сведений широкая, занимает большую часть области приложения и выровнена по правому краю.

Моя цель состоит в том, чтобы внедрить изменяемый фон изображения для каждой панели. Концепция будет похожа на механизм Android Nine Patch ( см. Документацию Nine Patch ). Фактически, это приложение WPF будет использовать те же исходные PNG, которые используются в версии Android того же приложения для Android. Как видите, это кроссплатформенное приложение. Он разделяет свои бизнес-объекты и логику на обеих платформах, но реализация интерфейса - это то, где приложения расходятся.

Когда вы читаете документы Nine Patch, игнорирует тот факт, что документы иллюстрируют эту концепцию только кнопками. Это может быть реализовано для любого вида. У меня уже есть концепция, работающая в iOS, включая фон приложения. Теперь мне просто нужно перенести концепцию на WPF и Silverlight.

Корневым контейнером каждой панели является System.Windows.Controls. Сетка . Из того, что я могу сказать, лучший способ справиться с этим - разделить сетку на структуру 3 на 3, а затем применить каждую часть изображения Nine Patch к каждому соответствующему разделу сетки с помощью привязок свойств WPF ... возможно, с помощью ImageBrush. Тем не менее, я не совсем знаком с построением гридов в WPF или с обязательной функцией в этом отношении. А как будет изменяться размер окна?

Любой совет по этому вопросу будет принята с благодарностью. Спасибо.

РЕДАКТИРОВАТЬ: Я должен также упомянуть, что в данном случае мне не предоставляется удобство XAML. Все это должно быть сделано программно.

РЕДАКТИРОВАТЬ: Просто хочу показать плоды совета loxxy и попросить дополнительных указаний на следующем шаге. Вот мои результаты реализации (у меня есть еще вопросы ниже, поэтому, пожалуйста, продолжайте читать):

Nine Patch for WPF

NinePatchImage npi = new NinePatchImage([some params]);
Grid backgroundGrid = new Grid();
backgroundGrid.ColumnDefinitions.Clear();
backgroundGrid.RowDefinitions.Clear();
backgroundGrid.ColumnDefinitions.Add(
    // first column
    new ColumnDefinition()
    {
        Width = new GridLength(1, GridUnitType.Auto),
    });
backgroundGrid.ColumnDefinitions.Add(
    // second column
    new ColumnDefinition()
    {
        Width = new GridLength(1, GridUnitType.Star)
    });
backgroundGrid.ColumnDefinitions.Add(
    // third column
    new ColumnDefinition()
    {
        Width = new GridLength(1, GridUnitType.Auto)
    });
backgroundGrid.RowDefinitions.Add(
    // first row
    new RowDefinition()
    {
        Height = new GridLength(1, GridUnitType.Auto),
    });
backgroundGrid.RowDefinitions.Add(
    // second row
    new RowDefinition()
    {
        Height = new GridLength(1, GridUnitType.Star)
    });
backgroundGrid.RowDefinitions.Add(
    // third row
    new RowDefinition()
    {
        Height = new GridLength(1, GridUnitType.Auto)
    });

var imageTopLeft = new Image() { Source = (npi.TopLeft != null) ? npi.TopLeft : null, Stretch = Stretch.None };
var imageTopCenter = new Image() { Source = (npi.TopCenter != null) ? npi.TopCenter : null, Stretch = Stretch.None };
var imageTopRight = new Image() { Source = (npi.TopRight != null) ? npi.TopRight : null, Stretch = Stretch.None };
var imageMiddleLeft = new Image() { Source = (npi.MiddleLeft != null) ? npi.MiddleLeft : null, Stretch = Stretch.None };
var imageMiddleCenter = new Image() { Source = (npi.MiddleCenter != null) ? npi.MiddleCenter : null, Stretch = Stretch.None };
var imageMiddleRight = new Image() { Source = (npi.MiddleRight != null) ? npi.MiddleRight : null, Stretch = Stretch.None };
var imageBottomLeft = new Image() { Source = (npi.BottomLeft != null) ? npi.BottomLeft : null, Stretch = Stretch.None };
var imageBottomCenter = new Image() { Source = (npi.BottomCenter != null) ? npi.BottomCenter : null, Stretch = Stretch.None };
var imageBottomRight = new Image() { Source = (npi.BottomRight != null) ? npi.BottomRight : null, Stretch = Stretch.None };

backgroundGrid.Children.Add(imageTopLeft); Grid.SetColumn(imageTopLeft, 0); Grid.SetRow(imageTopLeft, 0);
backgroundGrid.Children.Add(imageTopCenter); Grid.SetColumn(imageTopCenter, 1); Grid.SetRow(imageTopCenter, 0);
backgroundGrid.Children.Add(imageTopRight); Grid.SetColumn(imageTopRight, 2); Grid.SetRow(imageTopRight, 0);
backgroundGrid.Children.Add(imageMiddleLeft); Grid.SetColumn(imageMiddleLeft, 0); Grid.SetRow(imageMiddleLeft, 1);
backgroundGrid.Children.Add(imageMiddleCenter); Grid.SetColumn(imageMiddleCenter, 1); Grid.SetRow(imageMiddleCenter, 1);
backgroundGrid.Children.Add(imageMiddleRight); Grid.SetColumn(imageMiddleRight, 2); Grid.SetRow(imageMiddleRight, 1);
backgroundGrid.Children.Add(imageBottomLeft); Grid.SetColumn(imageBottomLeft, 0); Grid.SetRow(imageBottomLeft, 2);
backgroundGrid.Children.Add(imageBottomCenter); Grid.SetColumn(imageBottomCenter, 1); Grid.SetRow(imageBottomCenter, 2);
backgroundGrid.Children.Add(imageBottomRight); Grid.SetColumn(imageBottomRight, 2); Grid.SetRow(imageBottomRight, 2);

Grid contentArea = new Grid() { ColumnDefinitions = { new ColumnDefinition() } };
// setup contentArea here blah blah blah

// a containing grid
Grid container = new Grid();
// add the background grid to the containing grid
container.Children.Add(backgroundGrid);
// add the content grid to the background grid's UIElement collection
backgroundGrid.Children.Add(contentArea);
// set the backgroundGrid's column position
Grid.SetColumn(backgroundGrid, 0);
// set the backgroundGrid's row position
Grid.SetRow(backgroundGrid, 0);
// set the content area's column position
Grid.SetColumn(contentArea, 1);
// set the content area's row position
Grid.SetRow(contentArea, 1);

СЕЙЧАС, мне нужно, чтобы верхние и боковые изображения растягивались или располагались в правильном направлении, x или y. Элемент Image WPF имеет свойство растягивания с несколькими опциями, но растяжение происходит в обоих направлениях x и y, тогда как мне нужно растянуть только в одном из этих двух измерений. Кроме того, при необходимости (как в случае с вышеупомянутым изображением), я должен быть в состоянии TILE в x или y. Элемент image не поддерживает это, но я вижу, что класс ImageBrush может быть очень полезен для такого рода вещей. Может ли ImageBrush быть привязан непосредственно к элементу Image или любому другому типу элемента в этом отношении ??

1 Ответ

2 голосов
/ 03 августа 2011

Как вы думаете, зачем нужна сетка 3х3, если вам нужны две панели (как в ссылке). Если это просто фон, то ImageBrush достаточно, чтобы по-разному нарисовать две панели.

Кроме того, я бы предпочел DockPanel вместо этого, когда речь идет о выравнивании панелей вправо, влево и т. Д. Последний дочерний элемент в док-панели растягивается для заполнения родительского контейнера.

Я не получил ту часть, которую вы пытаетесь сделать с привязкой. Вы говорите о связывании контента внутри панелей? Или вы пытаетесь связать фоновое изображение с каким-нибудь источником?


Я прочитал документы на девять патчей, хотя не смог найти этот девять патчей, относящихся к девяти различным изображениям. Я чувствовал, что ninepatch - это просто растягиваемое изображение с рамкой.

В любом случае, если вы хотите использовать в качестве фона девять изображений, вы можете использовать изображения внутри дочерней сетки. Если вы поместите несколько элементов в сетку (в одну строку и столбец), последний дочерний элемент займет самый верхний слой сетки.

<Grid>
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="*" />
                    <RowDefinition Height="*"/>
                    <RowDefinition Height="*"/>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*"/>
                    <ColumnDefinition Width="*"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>

                <Image Source="Img1.png" Grid.Row="0" Grid.Column="0"/>
                <Image Source="Img2.png" Grid.Row="0" Grid.Column="1"/>
                <Image Source="Img3.png" Grid.Row="0" Grid.Column="2"/>
                <Image Source="Img4.png" Grid.Row="1" Grid.Column="0"/>
                <Image Source="Img5.png" Grid.Row="1" Grid.Column="1"/>
                <Image Source="Img6.png" Grid.Row="1" Grid.Column="2"/>
                <Image Source="Img7.png" Grid.Row="2" Grid.Column="0"/>
                <Image Source="Img8.png" Grid.Row="2" Grid.Column="1"/>
                <Image Source="Img9.png" Grid.Row="2" Grid.Column="2"/>
            </Grid>

            <Grid>
                <Label>This Content is put in front.</Label>
            </Grid>
</Grid>

Теперь обязательная часть. Вы динамически обновляете источники изображений? Я имею в виду изменить источник изображения на девять изображений? Тогда требуется только привязка. Если это просто источник, почему бы не указать URI напрямую.

Но если вам действительно нужно связывание,

<Image Source="{Binding ImagePath}" />

где ImagePath - строка. Это использует встроенный конвертер, который позволяет указывать источник изображения в виде строки.

Однако, чтобы избежать проблем (в серебряном переплете), вы можете использовать свой собственный конвертер.

public sealed class ImageConverter : IValueConverter
{
    public object Convert(object value, Type targetType,
                          object parameter, CultureInfo culture)
    {
        try
        {
            return new BitmapImage(new Uri((string)value));
        }
        catch 
        {
            return new BitmapImage();
        }
    }

    public object ConvertBack(object value, Type targetType,
                              object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Реализовать конвертер в привязке как

<Image Source="{Binding Path=ImagePath, Converter=...}" />
...