2010-12-28 11 views
15

मैं एक व्यूबॉक्स (या कुछ समान) बनाना चाहता हूं जो केवल इसकी ऊंचाई को स्केल करता है, और फिर क्षैतिज रूप से इसकी सामग्री को फैलाता है।लंबवत रूप से एक व्यूबॉक्स स्केल बनाना, क्षैतिज रूप से

अगर मैं ऐसा करते हैं:

http://www.excastle.com/misc/viewbox-center.png

यह कार्य करता है के रूप में अगर बटन के दोनों था HorizontalAlignment = "केन्द्र", और उसके बाद परिणाम मापता है:

<Viewbox> 
    <StackPanel> 
    <Button>Foo</Button> 
    <Button>Bar</Button> 
    </StackPanel> 
</Viewbox> 

तो मैं इस मिल । लेकिन मैं क्षैतिज चेतावनी = "केंद्र" नहीं चाहता; मैं चाहता हूँ HorizontalAlignment = "मांसपेशियों", इस तरह:

http://www.excastle.com/misc/viewbox-stretch.png

तो मैं इसे, उसकी सामग्री 'वांछित ऊंचाई केवल पढ़ने के लिए ऊंचाई के आधार पर एक स्केलिंग कारक की गणना, और फिर स्केल की गई सामग्री को फैलाने के लिए अनुमति देना चाहते हैं क्षैतिज।

क्या व्यूबॉक्स, और/या कुछ तृतीय-पक्ष पैनल का उपयोग करके इसे पूरा करने का कोई तरीका है?

उत्तर

16

डब्ल्यूपीएफ के साथ ऐसा कोई नियंत्रण शामिल नहीं है लेकिन आप बिना किसी परेशानी के अपने आप को लिख सकते हैं।यहाँ अपने विनिर्देशों है कि एक कस्टम ViewboxPanel है:

public class ViewboxPanel : Panel 
{ 
    private double scale; 

    protected override Size MeasureOverride(Size availableSize) 
    { 
     double height = 0; 
     Size unlimitedSize = new Size(double.PositiveInfinity, double.PositiveInfinity); 
     foreach (UIElement child in Children) 
     { 
      child.Measure(unlimitedSize); 
      height += child.DesiredSize.Height; 
     } 
     scale = availableSize.Height/height; 

     return availableSize; 
    } 

    protected override Size ArrangeOverride(Size finalSize) 
    { 
     Transform scaleTransform = new ScaleTransform(scale, scale); 
     double height = 0; 
     foreach (UIElement child in Children) 
     { 
      child.RenderTransform = scaleTransform; 
      child.Arrange(new Rect(new Point(0, scale * height), new Size(finalSize.Width/scale, child.DesiredSize.Height))); 
      height += child.DesiredSize.Height; 
     } 

     return finalSize; 
    } 
} 

और आप इस तरह इसका इस्तेमाल:

<local:ViewboxPanel> 
    <Button>Foo</Button> 
    <Button>Bar</Button> 
</local:ViewboxPanel> 

यह निश्चित रूप से कुछ काम करने की जरूरत है, लेकिन यह हो सकती है कि आप शुरू कर दिया।

+0

महान समाधान के लिए धन्यवाद। मैंने 'जोड़ा है (यदि सिस्टम (कॉम्पोनेंट मॉडेल.डिज़ाइनरप्रॉपर्टीज.गेटआईएस इनडिज़ीनमोड (यह)) { उपलब्ध आकार = नया आकार (200, 200); } ' विधि 'संरक्षित ओवरराइड आकार मापऑवर्राइड (आकार उपलब्ध आकार)' में डिज़ाइनर इसलिए अपवाद फेंकने के बिना काम करता है। – Mike

0

मुझे पूरा यकीन है कि उत्तर "आसानी से नहीं" है।

यहाँ एक विचार काम करने के लिए लगता है कि है, लेकिन यह एक तरह का भद्दा है:

  1. एक UserControl (नीचे उदाहरण में UserControl1) में अपने StackPanel फेंक।

  2. इस उपयोगकर्ता नियंत्रण की दो प्रतियां एक कंटेनर में रखें (नीचे दिए गए उदाहरण में एक ग्रिड)।

    ए। पहली प्रतिलिपि शीर्ष/बाएं संरेखित करें ताकि यह इसके डिफ़ॉल्ट आकार में बनी रहे। यह प्रति सख्ती से माप उद्देश्यों के लिए है और इसकी दृश्यता छिपी हुई होनी चाहिए।

    बी। दूसरी प्रतिलिपि को एक व्यूबॉक्स में रखें। यह प्रतिलिपि वह उपयोगकर्ता है जिसे उपयोगकर्ता वास्तव में देखेगा।

  3. दूसरा UserControl की चौड़ाई समायोजित करने के लिए एक MultiValueConverter के साथ एक MultiBinding का प्रयोग इतना है कि यह सही पहलू अनुपात पहले यह Viewbox से विस्तार हो जाता है।

यहाँ मार्कअप है:

<Grid> 
    <local:UserControl1 x:Name="RawControl" HorizontalAlignment="Left" VerticalAlignment="Top" Visibility="Hidden" /> 
    <Viewbox> 
     <local:UserControl1> 
      <local:UserControl1.Width> 
       <MultiBinding Converter="{StaticResource WidthAdjuster}"> 
        <Binding ElementName="RawControl" Path="ActualHeight" /> 
        <Binding RelativeSource="{RelativeSource AncestorType=Grid}" Path="ActualWidth" /> 
        <Binding RelativeSource="{RelativeSource AncestorType=Grid}" Path="ActualHeight" /> 
       </MultiBinding> 
      </local:UserControl1.Width> 
     </local:UserControl1> 
    </Viewbox> 
</Grid> 

यहाँ MultiValueConverter है

public class WidthAdjuster : IMultiValueConverter 
{ 
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 
    { 
     var rawHeight = (double)values[0]; 
     var containerWidth = (double)values[1]; 
     var containerHeight = (double)values[2]; 
     var ratio = containerWidth/containerHeight; 
     return rawHeight * ratio; 
    } 

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

परिणाम के लिए 525 x 350 कंटेनर

alt text

4

सही ढंग से काम करने के लिए चौड़ाई रखने के लिए:

protected override Size MeasureOverride(Size availableSize) 
    { 
     double height = 0; 
     Size unlimitedSize = new Size(double.PositiveInfinity, double.PositiveInfinity); 
     foreach (UIElement child in Children) 
     { 
      child.Measure(unlimitedSize); 
      height += child.DesiredSize.Height; 
     } 
     scale = availableSize.Height/height; 

     foreach (UIElement child in Children) 
     { 
      unlimitedSize.Width = availableSize.Width/scale; 
      child.Measure(unlimitedSize); 
     }   

     return availableSize; 
    } 
0

मैं एक लगभग समान समस्या थी। मेरे पैनल को अपने सभी बच्चों को फिट करना था, एक पंक्ति में थाम रखना और उन्हें खींचना, पैनल को समान रूप से भरना था। उपरोक्त एल्गोरिदम स्केल तत्वों में परिवर्तन प्रस्तुत करता है। समस्या यह है कि प्रतिपादन बच्चों को खुद को फैलाता है, लेकिन मार्जिन को अनदेखा करता है। यदि मार्जिन उच्च है और स्केल गुणांक 1 से नीचे है, तो तत्व पैनल से बाहर निकलते हैं। आपको उस अक्ष पर मार्जिन के अनुसार रेंडरट्रांसफॉर्म के लिए स्केल को सही करना होगा और व्यवस्था के लिए समान पैमाने गुणांक का उपयोग करना होगा। MeasureOverride मैं इस्तेमाल किया था

protected override Size MeasureOverride(Size availableSize) 
{ 
    double width = 0; double maxHeight = 0; double mY=0; double mX=0; 
    Size unlimitedSize = new Size(double.PositiveInfinity, double.PositiveInfinity); 
    foreach (UIElement child in Children) 
    { 
     child.Measure(unlimitedSize); 
     width += child.DesiredSize.Width; 
     maxHeight = Math.Max(maxHeight, child.DesiredSize.Height); 

     FrameworkElement cld = child as FrameworkElement; 
     mY = cld.Margin.Top + cld.Margin.Bottom; 
     mX = cld.Margin.Left + cld.Margin.Right; 
    } 

    double scaleX = availableSize.Width/width; 
    double scaleY = availableSize.Height/maxHeight; 
    //That is scale for arranging 
    positionScaling = Math.Min(scaleX, scaleY); 

    try 
    { 
     // Let FrameworkElement hight be Xn. mY = Element.Margin.Top + Element.Margin.bottom. 
     // DesiredSize includes margin therefore: 
     // (Yn + mY) * scaleY = availableSize.Height 
     // But render transform doesn't scales margin. Actual render height with margin will be 
     // Yn * RenderScaleY + mY = availableSize.Height; 
     // We must find render transform scale coeff like this: 

     double yn = availableSize.Height/scaleY - mY; 
     scaleY = (availableSize.Height - mY)/yn; 

     double xn = availableSize.Width/scaleX - mX; 
     scaleX = (availableSize.Width - mX)/xn; 


     scale = Math.Min(scaleX, scaleY); //scale to use in RenderTransform 
     // In my project all children are similar in size and margin, algorithm BREAKS otherwise!!! 
    } 
    catch { scale = 1; } 

    return availableSize; 
} 

एक बार फिर: अपने प्रोजेक्ट में सभी बच्चों के आकार और मार्जिन में समान हैं, एल्गोरिथ्म अन्यथा टूट जाता है।

संबंधित मुद्दे