Search code examples
c#wpfxamlprism

WPF Display only part of image


I'm writing an app in WPF Prism using MVVM model. I've an image that has height of 50px and width of 5000px. I need to show only a part of this image 100px width, and this part will differ based on user interaction. What I want to achieve is the ability to dynamically cut part of image defined by DispalyStart and DispalyWidth properties, where DispalyStart will be the start od rectangle to display and DispalyWidth will be a const of 100. The user shall somehow manipulate DisplayStart (gesture, button, or so on) to change the part of an image that is being displayed. What I've tried to do: Loaded the whole image and tried to display it's part using Image.Clip Rectangle Geometry: DisplayControl.xaml:

<Image x:Name="scale" Style="{DynamicResource Scale}">
        <Image.Clip>
            <RectangleGeometry Rect="{Binding ImageRect}" />
        </Image.Clip>
    </Image>

DispalyControlViewModel.cs:

private const int DisplayWidth = 100;
        public int Start {
            get { return _start; }
            set { SetProperty(ref _start, value); RaisePropertyChanged(nameof(ImageRect)); }
        }

        public Rect ImageRect {
            get { return new Rect(0, Start, textureHeight, DisplayWidth); }
        }

        private int _start = 0;
        private int textureHeight = 50;

The code above only produces line with color similar to test image (whole black with some colored lines to determine position).


Solution

  • You may simply create a CroppedBitmap whenever Start changes, and bind the Image's Source instead of its Clip. You would however also have the source bitmap in the view model.

    private const int displayWidth = 100;
    private int textureHeight = 50;
    private int start = 0;
    private BitmapSource source; // the original BitmapSource
    
    public int Start
    {
        get => start;
        set
        {
            SetProperty(ref start, value); 
            RaisePropertyChanged(nameof(CroppedImage));
        }
    }
    
    public BitmapSource CroppedImage => new CroppedBitmap(
        source,
        new Int32Rect(start, 0, displayWidth, textureHeight));
    

    Bind it like this:

    <Image x:Name="scale" Style="{DynamicResource Scale}"
           Source="{Binding CroppedImage}" />
    

    An alternative approach may utilize the Viewbox property of an ImageBrush: https://stackoverflow.com/a/22475123/1136211