मैं WPF राउंडेड कॉर्नर कंटेनर कैसे बनाऊं?


114

हम एक XBAP एप्लिकेशन बना रहे हैं, जिसके लिए हमें एक ही पृष्ठ में विभिन्न स्थानों में गोल कोनों की आवश्यकता है और हम भीतर अन्य तत्वों का एक गुच्छा रखने के लिए WPF राउंडेड कॉर्नर कंटेनर रखना चाहेंगे। क्या किसी के पास कोई सुझाव या नमूना कोड है कि हम इसे कैसे पूरा कर सकते हैं? या तो शैलियों के साथ या एक कस्टम नियंत्रण बनाने के साथ?


1
कैविएट: यदि आप एक गोल-आयत सीमा के अंदर पाठ की एक पंक्ति डालते हैं, तो मेरे जैसे पुराने लोग इसे देखेंगे और सोचेंगे, "मैकिंटोश का 80 का पुश बटन!"
mjfgates

आपको पता नहीं है कि मैं 80 के मैकिन्टोश को कितनी बुरी तरह याद करता हूँ! मुझे लगता है कि इस प्रश्न को स्पष्ट रूप से बताना चाहिए कि क्या कोनों की क्लिपिंग वांछित है या नहीं क्योंकि चयनित उत्तर सीमा को क्लिप नहीं करता है।
ATL_DEV

जवाबों:


266

आपको एक कस्टम नियंत्रण की आवश्यकता नहीं है, बस अपने कंटेनर को सीमा तत्व में रखें:

<Border BorderBrush="#FF000000" BorderThickness="1" CornerRadius="8">
   <Grid/>
</Border>

आप <Grid/>किसी भी लेआउट कंटेनर के साथ बदल सकते हैं ...


30
किसी भी मोटाई की वस्तु (बॉर्डरटीनेस या कॉर्नररेडियस) के लिए आप एक ही संख्या निर्दिष्ट कर सकते हैं यदि सभी 4 समान हैं, जैसे कॉर्नररेडियस = "8"।
सैंटियागो प्लादीनो

3
<Border BorderBrush="Black" BorderThickness="1" CornerRadius="8">इसके लिए एक उपयुक्त प्रतिस्थापन है, थोड़ा अधिक सक्सेस
किरेन जॉनस्टोन

@Patrik देवघर, मुझे गलत मत समझो, kobusb कमाल का है ... लेकिन मुझे लगता है कि WPF की टीम इसमें निर्माण के लिए भयानक थी और इसका फायदा उठाना इतना आसान था। (हालांकि कोई यह तर्क दे सकता है कि एक आधुनिक UI प्लेटफ़ॉर्म जिसके पास यह नहीं है ... वास्तव में एक आधुनिक UI प्लेटफ़ॉर्म नहीं है।)
19'12

1
वैसे, बॉर्डर का कार्यान्वयन बेहद ज्ञानवर्धक है ... यदि आपको लगता है कि कवर के नीचे खुदाई करना है। उदाहरण के लिए, यह कैसे स्ट्रीमगेमेट्री का उपयोग करता है ...
22

8
ठीक है, मुझे सीमा की मोटाई बढ़ाकर काम करने के लिए मिला, लेकिन यह समाधान कंटेनर के भीतर बच्चों के कोनों को क्लिप नहीं करता है। यह केवल बच्चों की ऊंचाई और चौड़ाई को सीमित करके कोनों को सीमा त्रिज्या को ओवरलैप करने से रोकता है। क्रिस कैवानघ का समाधान इस मामले को संभालता है। अफसोस की बात है, मैं उम्मीद कर रहा था कि यह समाधान काम करेगा क्योंकि यह अधिक कुशल और सुरुचिपूर्ण लगता है।
ATL_DEV

54

मुझे पता है कि यह प्रारंभिक प्रश्न का उत्तर नहीं है ... लेकिन आप अक्सर उस गोल कोने की सीमा की आंतरिक सामग्री को क्लिप करना चाहते हैं जिसे आपने अभी बनाया था।

क्रिस कैवनघ ने ऐसा करने का एक शानदार तरीका निकाला है ।

मैंने इसके लिए कुछ अलग तरीकों की कोशिश की है ... और मुझे लगता है कि यह एक चट्टान है।

यहाँ नीचे xaml है:

<Page
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Background="Black"
>
    <!-- Rounded yellow border -->
    <Border
        HorizontalAlignment="Center"
        VerticalAlignment="Center"
        BorderBrush="Yellow"
        BorderThickness="3"
        CornerRadius="10"
        Padding="2"
    >
        <Grid>
            <!-- Rounded mask (stretches to fill Grid) -->
            <Border
                Name="mask"
                Background="White"
                CornerRadius="7"
            />

            <!-- Main content container -->
            <StackPanel>
                <!-- Use a VisualBrush of 'mask' as the opacity mask -->
                <StackPanel.OpacityMask>
                    <VisualBrush Visual="{Binding ElementName=mask}"/>
                </StackPanel.OpacityMask>

                <!-- Any content -->
                <Image Source="http://chriscavanagh.files.wordpress.com/2006/12/chriss-blog-banner.jpg"/>
                <Rectangle
                    Height="50"
                    Fill="Red"/>
                <Rectangle
                    Height="50"
                    Fill="White"/>
                <Rectangle
                    Height="50"
                    Fill="Blue"/>
            </StackPanel>
        </Grid>
    </Border>
</Page>

1
Blacklight Controls ( blacklight.codeplex.com ) में ClippingBorder नाम का एक छोटा सा नियंत्रण भी है जो आपको सामग्री को अपने गोल कोनों पर क्लिप करने की अनुमति देता है। ClippingBorder के बारे में एक अच्छी बात यह है कि यह एक VisualBrush (जो उच्चतम लागत (प्रदर्शन के मामले में) ब्रश में से एक है) का उपयोग नहीं करता है।
cplotts

1
हालाँकि, मैंने अभी क्लिपिंगबोर्ड के कार्यान्वयन के अंदर एक नज़र डाली ... और यह अपने डिफ़ॉल्ट ControlTemplate (प्रत्येक कोनों में से एक के लिए) में 4 ContentControl (s) का उपयोग करता है ... इसलिए मुझे यकीन नहीं है कि यह अधिक या कम है ऊपर दिए गए VisualBrush दृष्टिकोण से बेहतर प्रदर्शन। मैं शायद कम प्रदर्शन करने वाले की कल्पना करूंगा।
cplotts

यदि क्लिपिंग की आवश्यकता होती है, तो इसका उत्तर चुना जाना चाहिए।
ATL_DEV

1
यह ऐसा करने का एकमात्र वास्तविक तरीका है! यह आश्चर्यजनक है कि यह एक सीमा के अंदर तत्वों के लिए डिफ़ॉल्ट व्यवहार नहीं है।
इरान ओत्ज़ाप

@eranotzap आपको यह जवाब पसंद आया। केवल नकारात्मक पक्ष यह है कि आप VisualBrush का उपयोग कर रहे हैं जो अधिक प्रदर्शन वाला भारी आइटम है। नीचे मेरा अन्य उत्तर आपको दिखाता है कि इस
विज़ुअलब्रश

14

मुझे बस खुद ऐसा करना था, इसलिए मैंने सोचा कि मैं यहां एक और उत्तर दूंगा।

यहां एक गोल कोने की सीमा बनाने और इसके आंतरिक सामग्री को क्लिप करने का एक और तरीका है । यह क्लिप संपत्ति का उपयोग करके सीधा तरीका है। यदि आप VisualBrush से बचना चाहते हैं तो यह अच्छा है।

Xaml:

<Border
    Width="200"
    Height="25"
    CornerRadius="11"
    Background="#FF919194"
>
    <Border.Clip>
        <RectangleGeometry
            RadiusX="{Binding CornerRadius.TopLeft, RelativeSource={RelativeSource AncestorType={x:Type Border}}}"
            RadiusY="{Binding RadiusX, RelativeSource={RelativeSource Self}}"
        >
            <RectangleGeometry.Rect>
                <MultiBinding
                    Converter="{StaticResource widthAndHeightToRectConverter}"
                >
                    <Binding
                        Path="ActualWidth"
                        RelativeSource="{RelativeSource AncestorType={x:Type Border}}"
                    />
                    <Binding
                        Path="ActualHeight"
                        RelativeSource="{RelativeSource AncestorType={x:Type Border}}"
                    />
                </MultiBinding>
            </RectangleGeometry.Rect>
        </RectangleGeometry>
    </Border.Clip>

    <Rectangle
        Width="100"
        Height="100"
        Fill="Blue"
        HorizontalAlignment="Left"
        VerticalAlignment="Center"
    />
</Border>

कनवर्टर के लिए कोड:

public class WidthAndHeightToRectConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        double width = (double)values[0];
        double height = (double)values[1];
        return new Rect(0, 0, width, height);
    }
    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

बहुत अच्छा समाधान। मैं एक बटन के लिए एक कंट्रोल टेम्प्लेट बना रहा हूं, जिसमें विभिन्न राज्यों में बाहरी चमक और आंतरिक चमक दोनों की आवश्यकता होती है, और इससे समस्या को हल करने में मदद मिली।
क्वांटा

2

कोबस बॉर्डर कंट्रोल समाधान का VB.Net कोड आधारित कार्यान्वयन। मैंने इसका उपयोग बटन नियंत्रणों की सूची बॉक्स को पॉप्युलेट करने के लिए किया था। बटन नियंत्रण MEF एक्सटेंशन से बनाए गए हैं। एक्सटेंशन के विवरण के लिए प्रत्येक एक्सटेंशन MEF के ExportMetaData विशेषता का उपयोग करता है। एक्सटेंशन विज़िफ़ायर चार्टिंग ऑब्जेक्ट हैं। उपयोगकर्ता वांछित चार्ट को निष्पादित करने के लिए बटन की सूची से चयनित एक बटन को धक्का देता है।

        ' Create a ListBox of Buttons, one button for each MEF charting component. 
    For Each c As Lazy(Of ICharts, IDictionary(Of String, Object)) In ext.ChartDescriptions
        Dim brdr As New Border
        brdr.BorderBrush = Brushes.Black
        brdr.BorderThickness = New Thickness(2, 2, 2, 2)
        brdr.CornerRadius = New CornerRadius(8, 8, 8, 8)
        Dim btn As New Button
        AddHandler btn.Click, AddressOf GenericButtonClick
        brdr.Child = btn
        brdr.Background = btn.Background
        btn.Margin = brdr.BorderThickness
        btn.Width = ChartsLBx.ActualWidth - 22
        btn.BorderThickness = New Thickness(0, 0, 0, 0)
        btn.Height = 22
        btn.Content = c.Metadata("Description")
        btn.Tag = c
        btn.ToolTip = "Push button to see " & c.Metadata("Description").ToString & " chart"
        Dim lbi As New ListBoxItem
        lbi.Content = brdr
        ChartsLBx.Items.Add(lbi)
    Next

Public Event Click As RoutedEventHandler

Private Sub GenericButtonClick(sender As Object, e As RoutedEventArgs)
    Dim btn As Button = DirectCast(sender, Button)
    Dim c As Lazy(Of ICharts, IDictionary(Of String, Object)) = DirectCast(btn.Tag, Lazy(Of ICharts, IDictionary(Of String, Object)))
    Dim w As Window = DirectCast(c.Value, Window)
    Dim cc As ICharts = DirectCast(c.Value, ICharts)
    c.Value.CreateChart()
    w.Show()
End Sub

<System.ComponentModel.Composition.Export(GetType(ICharts))> _
<System.ComponentModel.Composition.ExportMetadata("Description", "Data vs. Time")> _
Public Class DataTimeChart
    Implements ICharts

    Public Sub CreateChart() Implements ICharts.CreateChart
    End Sub
End Class

Public Interface ICharts
    Sub CreateChart()
End Interface

Public Class Extensibility
    Public Sub New()
        Dim catalog As New AggregateCatalog()

        catalog.Catalogs.Add(New AssemblyCatalog(GetType(Extensibility).Assembly))

        'Create the CompositionContainer with the parts in the catalog
        ChartContainer = New CompositionContainer(catalog)

        Try
            ChartContainer.ComposeParts(Me)
        Catch ex As Exception
            Console.WriteLine(ex.ToString)
        End Try
    End Sub

    ' must use Lazy otherwise instantiation of Window will hold open app. Otherwise must specify Shutdown Mode of "Shutdown on Main Window".
    <ImportMany()> _
    Public Property ChartDescriptions As IEnumerable(Of Lazy(Of ICharts, IDictionary(Of String, Object)))

End Class

1

यदि आप एक गोल-आयत सीमा में एक बटन लगाने की कोशिश कर रहे हैं, तो आपको msdn का उदाहरण देखना चाहिए । मुझे यह समस्या की छवियों (पाठ के बजाय) के लिए googling द्वारा मिला। उनकी भारी बाहरी आयत (शुक्र है) को हटाना आसान है।

ध्यान दें कि आपको बटन के व्यवहार को फिर से परिभाषित करना होगा (क्योंकि आपने कंट्रोलटेम्पलेट बदल दिया है)। यही है, आपको ControlTemplate.Triggers टैग में एक ट्रिगर टैग (संपत्ति = "IsPressed" Value = "true") का उपयोग करके क्लिक करने पर बटन के व्यवहार को परिभाषित करने की आवश्यकता होगी। उम्मीद है कि यह किसी और को खो देता है समय मैं खो दिया :)

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.