Заморозка части холста при прокрутке в WPF? - PullRequest
0 голосов
/ 13 марта 2019

Я новичок в WPF и XAML. Я работаю над интерфейсом рояля пианино для чтения MIDI-файлов, который пока выглядит примерно так: https://i.imgur.com/hBJZhnH.png

У меня есть холст для всего рулона пианино (обернутый вокруг ScrollViewer для горизонтальной и вертикальной прокрутки). На этом холсте у меня есть сетка grdPiano для рисования нот фортепиано, сетка grdGridColours для рисования цветов заливки горизонтальной строки, холст cnvGridLines, где я рисую вертикальные линии сетки (это делается в коде C #) и сетку grdNotes, где я рисую ноты MIDI в коде C #.

Это работает нормально, но когда я прокручиваю горизонтально, клавиши пианино (grdPiano) прокручиваются вне поля зрения. Я хочу, чтобы при прокрутке по вертикали все прокручивалось, но если прокручивать по горизонтали, клавиши пианино остаются замороженными в левой части экрана. Я возился с вложенными ScrollViewers, но не могу заставить его работать.

Вот мой XAML:

<ScrollViewer x:Name="srlPianoScroll"  Margin="125,20,0,0" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
    <Canvas x:Name="cnvPianoRoll" HorizontalAlignment="Left" Height="1592" VerticalAlignment="Center" Width="132">
        <Grid x:Name="grdPiano" HorizontalAlignment="Left" Height="1638" VerticalAlignment="Center" Width="132" Canvas.Top="-8">
            <Grid.RowDefinitions>
                <!--Row definitions...-->
            </Grid.RowDefinitions>
            <!--Drawing piano notes...-->
        </Grid>
        <Grid x:Name="grdGridColours" HorizontalAlignment="Left" Height="1628" VerticalAlignment="Center" Width = "0" Canvas.Top="2" Canvas.Left="132" Panel.ZIndex="1">
            <Grid.RowDefinitions>
                <!--Row definitions...-->
            </Grid.RowDefinitions>
            <!--Drawing horizontal fill colours...-->
        </Grid>
        <Canvas x:Name="cnvGridLines" HorizontalAlignment="Left" Height="1592" VerticalAlignment="Center" Width = "0" Canvas.Top="2" Canvas.Left="132" Panel.ZIndex="2"/>
            <!--Vertical grid lines are drawn programatically.-->
        <Grid x:Name="grdNotes" HorizontalAlignment="Left" Height="1628" VerticalAlignment="Center" Width = "0" Canvas.Top="2" Canvas.Left="132" Panel.ZIndex="3">
            <Grid.RowDefinitions>
                <!--Row definitions...-->
            </Grid.RowDefinitions>
        </Grid>
    </Canvas>
</ScrollViewer>

Спасибо!

1 Ответ

1 голос
/ 13 марта 2019

Попробуйте связать grdPiano's Canvas.Left с HorizontalOffset наблюдателя прокрутки.

Когда средство прокрутки прокручивается горизонтально, привязка обновит Canvas.Left так, чтобы он находился у левого края видимой области. При необходимости вы можете использовать конвертер для добавления смещения.

Вот пример:

1007 * XAML *

<Window x:Class="WpfApp38.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp38"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.Resources>
        <local:OffsetConverter x:Key="OffsetConverter" />
    </Window.Resources>
    <ScrollViewer Name="sv" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
        <Canvas Width="10600" Height="500">
            <!-- Rectangle that stays on the left side, your grdPiano -->
            <Rectangle Canvas.Left="{Binding ElementName=sv, Path=HorizontalOffset}" Canvas.Top="0" Width="50" Height="500" Fill="Blue" Panel.ZIndex="1" />

            <!-- Rectangle that stays on the left side, your grdPiano - - using the OffsetConverter to offset it 300 to the right -->
            <!--<Rectangle Canvas.Left="{Binding ElementName=sv, Path=HorizontalOffset, Converter={StaticResource OffsetConverter}, ConverterParameter=300}" Canvas.Top="0" Width="50" Height="500" Fill="LightBlue" Panel.ZIndex="1" />-->

            <!-- Rectangles that scrolls normally -->
            <Rectangle Canvas.Left="150" Canvas.Top="50" Width="200" Height="25" Fill="Black" />
            <Rectangle Canvas.Left="50" Canvas.Top="100" Width="100" Height="25" Fill="Black" />
            <Rectangle Canvas.Left="350" Canvas.Top="200" Width="250" Height="25" Fill="Black" />
            <Rectangle Canvas.Left="600" Canvas.Top="235" Width="10000" Height="25" Fill="Black" />
        </Canvas>
    </ScrollViewer>
</Window>

И код для конвертера:

public class OffsetConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is double scrollViewerHorizontalOffset && parameter is string s)
        {
            double offsetAmount;
            double.TryParse(s, out offsetAmount);

            return scrollViewerHorizontalOffset + offsetAmount;
        }
        return value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...